spawn without linking?

Dustin Sallings <>
Tue Apr 20 21:08:58 CEST 2004


On Apr 20, 2004, at 2:32, Joe Armstrong wrote:

> Things that you want to be independent should not be linked together.
>
> If you have two entirely different applications A and B you absolutely
> do not want A to be linked to B.
>
> If you have some error logger L then you *do* want L to be linked to A
> and L to be linked to B. Errors in A or B should be reported by L.

	I suppose I've been thinking about A and B both being launched by M 
(like init(8)) so there would always be a process ultimately 
responsible for everything.

> spawn_link could *almost* be defined like this:
>
> 	spawn_link(F) ->
> 		Pid = spawn(Fun),
> 		link(Pid),
> 		Pid.

	It was before I found spawn_link!  :)

> But this is not correct (Why? - the process might die *between* the 
> spawn
> and the link) - so spawn_link does spawn and link atomically.

	Definitely good to know.

> If you're new to Erlang I'd use spawn_link - as you build sexier 
> applications
> you should think *carefully* about what should happen when things die 
> and try to
> stop errors propagating between independent components.

	Yeah, I've no doubt a lot to learn.

> You might like to look at the documentation for erlang:monitor (do > 
> erl -man man erlang)
> - this sets up a asymmetric link - which is often very useful.

	I'm using erlang:monitor for an exercise, but I guess I'm not entirely 
sure how to deal with abnormal exits that are propagated by links.  For 
example, I've got the following code:

% Demo process
echo() ->
     receive
         {From, N} ->
             io:format("Sending back ~p from ~p\n", [N, self()]),
             From ! N,
             echo();
         stop ->
             io:format("Stopping ~p\n", [self()]),
             true;
         error ->
             exit("Got an error");
         Unknown ->
             error_logger:error_msg("~p exiting due to unhandled 
message:  ~p\n",
                 [self(), Unknown])
     end.

% Replace a process in a process list
mcpReplaceProcess(OldPid, Procs) ->
     NewProc = spawn_link(coursemp, echo, []),
     % erlang:monitor(process, NewProc),
     io:format("Created new proc ~p\n", [NewProc]),
     OtherProcs = lists:filter(fun (P) -> not(P == OldPid) end, Procs),
     [NewProc | OtherProcs].

% Listen for messages from the processes this thing controls
mcpLoop(Procs) ->
     io:format("Looping with procs:  ~p\n", [Procs]),
     receive
         {sendto, N, Msg} ->
             lists:nth(N, Procs) ! Msg,
             mcpLoop(Procs);
         {'DOWN', _Ref, process, Pid, _Flag} ->
             io:format("MCP got down message for ~p\n", [Pid]),
             mcpLoop(mcpReplaceProcess(Pid, Procs));
         Msg ->
             io:format("MCP got ~p\n", [Msg]),
             mcpLoop(Procs)
     end.

% Start up a bunch of processes and loop
mcpMonitor(N) ->
     Procs = listBuilder(fun () -> spawn_link(coursemp, echo, []) end, 
N, []),
     lists:foreach(fun (P) -> erlang:monitor(process, P) end, Procs),
     mcpLoop(Procs).

% Get an Mcp process controlling the given number of echo processes
mcp(N) ->
     spawn_link(coursemp, mcpMonitor, [N]).



	I'd like the 'error' message to be handled properly by the echo 
process in a similar fashion to what monitor is doing, but it seems to 
have different behavior:


1> Mcp = coursemp:mcp(5).
Looping with procs:  [<0.36.0>,<0.35.0>,<0.34.0>,<0.33.0>,<0.32.0>]
<0.31.0>
2> Mcp ! {sendto, 3, echo}.
Looping with procs:  [<0.36.0>,<0.35.0>,<0.34.0>,<0.33.0>,<0.32.0>]
{sendto,3,echo}

=ERROR REPORT==== 20-Apr-2004::12:03:40 ===
<0.34.0> exiting due to unhandled message:  echo
MCP got down message for <0.34.0>
Created new proc <0.39.0>
Looping with procs:  [<0.39.0>,<0.36.0>,<0.35.0>,<0.33.0>,<0.32.0>]
3> Mcp ! {sendto, 3, {Mcp, echo}}.
Looping with procs:  [<0.39.0>,<0.36.0>,<0.35.0>,<0.33.0>,<0.32.0>]
{sendto,3,{<0.31.0>,echo}}
Sending back echo from <0.35.0>
MCP got echo
Looping with procs:  [<0.39.0>,<0.36.0>,<0.35.0>,<0.33.0>,<0.32.0>]
4> Mcp ! {sendto, 3, stop}.
Looping with procs:  [<0.39.0>,<0.36.0>,<0.35.0>,<0.33.0>,<0.32.0>]
{sendto,3,stop}
Stopping <0.35.0>
MCP got down message for <0.35.0>
Created new proc <0.42.0>
Looping with procs:  [<0.42.0>,<0.39.0>,<0.36.0>,<0.33.0>,<0.32.0>]
5> Mcp ! {sendto, 3, die}.
Looping with procs:  [<0.42.0>,<0.39.0>,<0.36.0>,<0.33.0>,<0.32.0>]
{sendto,3,die}

=ERROR REPORT==== 20-Apr-2004::12:04:04 ===
<0.36.0> exiting due to unhandled message:  die
MCP got down message for <0.36.0>
Created new proc <0.44.0>
Looping with procs:  [<0.44.0>,<0.42.0>,<0.39.0>,<0.33.0>,<0.32.0>]
6> Mcp ! {sendto, 3, error}.
Looping with procs:  [<0.44.0>,<0.42.0>,<0.39.0>,<0.33.0>,<0.32.0>]
{sendto,3,error}
** exited: "Got an error" **
7> Mcp ! {sendto, 3, die}.
{sendto,3,die}

	As of the 'error' message, the Mcp has died.  Does this mean the Mcp 
should *not* be linked to the processes it controls, or is there a 
different way to handle the errors?

	Thanks for your help.  Erlang may prove to be pretty useful in my line 
of work.

-- 
Dustin Sallings




More information about the erlang-questions mailing list