Reputation: 785
I have written the following code:
-module(ring).
-export([start/3]).
start(1, 1, Message) -> %special case, no new processes to be launched
io:format(" Start/3, branch 1~n~n"),
loop(self(), 1, 1),
self() ! Message,
self() ! {self(), quit};
start(1, MsgNum, Message) when MsgNum > 1 -> %first process, register self, launch next, send message, loop
io:format(" Start/3 branch 2, ProcNum: ~b, MsgNum: ~b, process: ~p~n~n", [1, MsgNum, self()]),
register(process_1, self()),
self() ! {self(), Message},
NextPid = spawn(ring, start, [2, MsgNum, Message]),
NextPid ! {self(), Message},
loop(NextPid, 1, MsgNum);
start(MsgNum, MsgNum, _) when MsgNum >= 1 -> %last process, don't start new process, quit master, run loop
io:format(" Start/3 branch 3, MsgNum = ProcNum = ~b, process: ~p~n~n", [MsgNum, self()]),
process_1 ! {self(), quit},
loop(process_1, MsgNum, MsgNum);
start(ProcNum, MsgNum, Message) when ProcNum >= 1 -> %everything else, start next process, send it a message, start loop
io:format(" Start/3 branch 4, ProcNum: ~b, MsgNum: ~b, process: ~p~n~n", [ProcNum, MsgNum, self()]),
NextPid = spawn(ring, start, [ProcNum + 1, MsgNum, Message]),
NextPid ! {self(), Message},
loop(NextPid, ProcNum, MsgNum).
loop(NextPid, ProcNum, MsgNum) ->
receive
{Sender, quit} -> % send quit to next process in queue, then terminate with 'ok'
io:format(" Sender: ~p Quitting process ~p Next: ~p~n~n", [Sender, self(), NextPid]),
NextPid ! {self(), quit},
ok;
{Sender, Msg} -> % print message and wait for next message
io:format(" Message: ~w~n procNum: ~b msgNum: ~b sender: ~p self: ~p next: ~p~n~n", [Msg, ProcNum, MsgNum, Sender, self(), NextPid]),
loop(NextPid, ProcNum, MsgNum);
_ -> %flush garbage, should never get here...
io:format(" Oops. Received someting unexpected")
end.
I expect this code to launch a series of processes, which should each print one message, then politely quit. For example, if I run ring:start(1,3,hola), I expect to see three processes, three messages, and three quits. And it almost works, except that the initial process does not terminate, as seen in this shell session:
Eshell V5.10.1 (abort with ^G)
1> c(ring).
{ok,ring}
2> processes().
[<0.0.0>,<0.3.0>,<0.6.0>,<0.7.0>,<0.9.0>,<0.10.0>,<0.11.0>,
<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,<0.16.0>,<0.17.0>,
<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,<0.22.0>,<0.23.0>,
<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,<0.28.0>,<0.32.0>]
3> ring:start(1,3,hola).
Start/3 branch 2, ProcNum: 1, MsgNum: 3, process: <0.32.0>
Message: hola
procNum: 1 msgNum: 3 sender: <0.32.0> self: <0.32.0> next: <0.41.0>
Start/3 branch 4, ProcNum: 2, MsgNum: 3, process: <0.41.0>
Message: hola
procNum: 2 msgNum: 3 sender: <0.32.0> self: <0.41.0> next: <0.42.0>
Start/3 branch 3, MsgNum = ProcNum = 3, process: <0.42.0>
Message: hola
procNum: 3 msgNum: 3 sender: <0.41.0> self: <0.42.0> next: process_1
Sender: <0.42.0> Quitting process <0.32.0> Next: <0.41.0>
Sender: <0.32.0> Quitting process <0.41.0> Next: <0.42.0>
Sender: <0.41.0> Quitting process <0.42.0> Next: process_1
ok
4> processes().
[<0.0.0>,<0.3.0>,<0.6.0>,<0.7.0>,<0.9.0>,<0.10.0>,<0.11.0>,
<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,<0.16.0>,<0.17.0>,
<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,<0.22.0>,<0.23.0>,
<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,<0.28.0>,<0.32.0>]
I apologize for the long code/log blocks, but I think this makes it pretty clear that start/3 causes three processes to be launched (<0.32.0>, <0.41.0>, and <0.42.0>), and that each prints one message, and each receives its quit message. However, when all is done, the initial process (<0.32.0>) is still running. My understanding is that the process should terminate once there is no more code to run -- is there something special about the first process that prevents its termination?
Thanks in advance.
Upvotes: 0
Views: 230
Reputation: 2040
Your function start/3 does not start the process you call 'initial'. Instead the function runs in the process which is already exists. This is the process of erlang shell and you are working with it. It has pid <0.32.0>. Look carefully at the output of the first call of the function processes():
2> processes().
[<0.0.0>,<0.3.0>,<0.6.0>,<0.7.0>,<0.9.0>,<0.10.0>,<0.11.0>,
<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,<0.16.0>,<0.17.0>,
<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,<0.22.0>,<0.23.0>,
<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,<0.28.0>,<0.32.0>]
The last pid in list is <0.32.0>. So when you call start/3 it runs within that process and when it exits from loop the process <0.32.0> will not be finished - it will only returns to erlang shell and wait next command.
Upvotes: 4