实际上有两种方法可以解决这个问题。
第一个是:控制spawns
环中的所有工人,这是解决方案:
-module(ring).
-export([start/3, create/4]).
start(M, N, Message) ->
create(undef, N, M, Message).
create(Parent, 0, M, Message) ->
Parent ! {created, self()},
evaluate(Parent, M, Message);
create(Parent, N, M, Message) ->
Child = spawn(?MODULE, create, [self(), N-1, M, Message]),
io:format("~w ~w created~n", [Child, N]),
evaluate(Parent, M, Message).
evaluate(undef, M, Message) ->
receive
{created, Last} ->
Last ! Message,
io:format("~w sent ~w to ~w~n", [self(), Message, Last]),
evaluate(Last, M-1, Message)
end;
evaluate(Parent, 0, _) ->
receive
Msg ->
io:format("~w received ~w~n", [self(), Msg]),
Parent ! stop,
io:format("~w sent ~w to ~w~n", [self(), stop, Parent])
end;
evaluate(Parent, M, Message) ->
receive
{created, Last} ->
Parent ! {created, Last},
evaluate(Parent, M, Message);
Message ->
io:format("~w received ~w~n", [self(), Message]),
Parent ! Message,
io:format("~w sent ~w to ~w~n", [self(), Message, Parent]),
evaluate(Parent, M-1, Message)
end.
而第二个是:spawns
只控制环中的第一个工人。环中的每个新工人,除了最后一个工人,都会产生下一个工人:
-module(ring).
-export([start/3, start_process/1, start_process/2]).
start(M, N, Message) ->
Pid = spawn(ring, start_process, [N]),
Pid ! {message, Message, M},
ok.
start_process(Count) ->
% This is the first spawned process - send its
% pid down the chain so the last process knows who its
% next pid is.
io:format("~p: Spawned ~p~n", [self(), Count]),
Pid = spawn(ring, start_process, [Count-1, self()]),
loop(Pid).
start_process(0, Last) ->
% This is the last process
io:format("~p: Linking to last ~p~n", [self(), Last]),
loop(Last);
start_process(Count, Last) ->
io:format("~p: Spawned ~p~n", [self(), Count]),
Pid = spawn(ring, start_process, [Count-1, Last]),
loop(Pid).
loop(NextPid) ->
receive
{message, _, 0} -> true;
{message, Msg, M} ->
io:format("~p (~p) ~p~n", [Msg, self(), M]),
NextPid ! {message, Msg, M-1},
loop(NextPid)
end.