In Erlang, processes can be linked to each other. If two processes are linked to each other and one of them terminates abnormally, the other one will automatically terminate.
In the file
module-8/mandatory/src/link.erl
you find the following Erlang program.
-module(link).
-export([start/0]).
start() ->
spawn(fun() -> worker() end),
timer:sleep(5000).
worker() ->
timer:sleep(3000),
exit(some_error).
The start/0
function spawns a new process running the worker/0
function and
then sleeps for 5 seconds. The worker/0
function first sleeps for 3 seconds
and then terminates the calling process with the atom some_error
as the exit
reason.
Exit reason
In the above example, the atom some_error
is used as the exit reason but you can
change this to any valid Erlang term.
In the terminal, navigate to the directory module-8/mandatory/src
.
$ cd module-8/mandatory/src
Start an Erlang shell.
$ erl
You should now see the Erlang shell starting.
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:10] [kernel-poll:false]
Eshell V9.2 (abort with ^G)
erlang>
Compile the link.erl
module. Don’t forget end the expression with a trailing
.
(dot).
erlang> c(link).
On success you now should see the following in the Erlang shell.
{ok, link}
erlang>
Run the program from the Erlang shell.
erlang> link:start().
After 5 seconds both process has terminated and you should see the following in the Erlang shell.
ok
erlang>
Here ok
means that the program terminated without errors. Although the worker
process terminated with reason some_error
the parent process terminated
without errors.
The built in function spawn_link/1
can be used to spawn a new process and set
up a link between the calling process and the new process. Change link.erl
to
use spawn_link
.
-module(link).
-export([start/0]).
start() ->
spawn_link(fun() -> worker() end),
timer:sleep(5000).
worker() ->
timer:sleep(3000),
exit(some_error).
Compile and run.
3> c(link).
{ok, link}
erlang> link:start().
After 3 seconds you should now see the following in the Erlang shell.
** exception exit: some_error
erlang>
When a link is setup between two processes and one of the two processes terminates, the other process automatically terminates with the same reason. Behind the scenes, the Erlang runtime sends an exit signal to terminate the linked process.
A process can be set to trap the exit signal by setting the trap_exit
process
flag to true
.
process_flag(trap_exit, true)
A process that traps the exit signal will receive a message when a linked process terminates. The message has the following format:
{'EXIT', PID, Reason}
, i.e., a 3-tuple where the first element is the atom ‘EXIT’, the second element is the process id of the terminated process and the third element is the exit reason.
Make the parent process trap the exit signal. Also, make the parent process wait for the exit message.
-module(link).
-export([start/0]).
start() ->
process_flag(trap_exit, true),
spawn_link(fun() -> worker() end),
receive
{'EXIT', PID, Reason} ->
io:format("Worker ~p terminated with reason ~w!~n", [PID, Reason])
end.
worker() ->
timer:sleep(3000),
exit(some_error).
Compile and run.
erlang> c(link).
{ok, link}
erlang> link:start().
After 3 seconds you should now see something similar to the following in the Erlang shell.
Worker <0.79.0> terminated with reason some_error!
ok
erlang>
Now, when the worker process terminates, the parent process is notified by an exit message. After receiving the exit message, the parent prints a short message and then terminates normally.