Erlang (programming language)/Tutorials/Trap exit

From Citizendium
Jump to navigation Jump to search

Trapping Exit Signals

Trapping Exit Signals is one of the most elegant parts of erlang. Under certain conditions we can cause the error message of a crashing process to be turned into a regular message to another process that is watching. In the example program we construct a monitor-worker relationship. A monitor process is watching a worker process. First we spawn the monitor, then we spawn the worker. We need to link the two processes. Then we change the process flag for trap_exit to true.

start() ->
  spawn( monitor...
  spawn( worker...
monitor() ->
  ...
  link(worker).
  process_flag(trap_exit, true).
  ...

When trap_exit==true then monitor behaves like a system process and receives exit messages from its workers. Normally, a monitor process will exit with its linked worker. After trap_exit=true, if the worker exits then the monitor receives an {EXIT, Pid, Why} message. If the monitor wishes, it could restart the worker or do some other needed action based on the type of exit condition.

In the example code we take the log of 10, 1 and 0. Of course log(10) and log(1) have values but log(0) is undefined and causes the worker process to exit with a badarith(bad arithmatic) error.

Sample Program

%% ---
%%  trap_exit_test
%%    a simple demo of using trap_exit
%%---
-module(trap_exit_test).
-compile(export_all).

start() ->
       Pid = spawn(trap_exit_test, worker, []),
       register(work, Pid),
       spawn(trap_exit_test, monitor, [Pid]),
       work ! {log,10}, sleep(1000),
       work ! {log,1},	 sleep(1000),
       work ! {log,0}.
monitor(Pid) ->
       link(Pid),
       process_flag(trap_exit, true),
       receive
               {'EXIT', _Pid, Why} ->
                       io:format("worker exit: ~w  
                                  ~n",[Why]),
                       exit(monitor_normal_exit)
       end,
       monitor(Pid).

worker() ->
       receive
              {log, Arg} ->
                       Output = math:log(Arg),
                       io:format("log of ~w = ",[Arg]),
                       io:format("~w ~n",[Output])
       after 5000 -> 
              exit(time_out)
       end,
       worker().
sleep(T) ->
       receive
       after T -> ok
       end.

Sample Output

1> c(trap_exit_test).
{ok,trap_exit_test}

2> trap_exit_test:start().
log of 10 = 2.30259 
log of 1 = 0.00000e+0 

=ERROR REPORT==== 12-Jul-2008::10:40:53 ===
Error in process <0.37.0> with exit value:  
{badarith,[{math,log,[0]},{trap_exit_test,worker,0}]}

worker exit:  
{badarith,[{math,log,[0]},{trap_exit_test,worker,0}]} 
{log,0}