Exercise 4-2: The Process Ring

862 views
Skip to first unread message

Andrey

unread,
Nov 10, 2009, 10:12:23 PM11/10/09
to Erlang Programming
Hey guys, below is my solution. Critique is welcome.

Andrey

-------------

%%
%% Solution for Exercise 4-2 from book "Erlang Programming", p.115
%% 1> ring:start(2, 5, message).
%%
-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.

Emil Ivanov

unread,
Nov 15, 2009, 1:02:34 PM11/15/09
to Erlang Programming
Hello Andrey,

If I'm not mistaking - you've opted for the second approach - each
process spawning the next.

I also went the same way. Below is the code:

-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.

I would love to see a solution where the ring is set up by the central
process. I tries to do one, but couldn't wrap my head around it.

Regards,
Emil Vladev

--
http://bolddrea.com

Sami

unread,
Jan 4, 2010, 5:27:55 PM1/4/10
to Erlang Programming
hi,
here is a solution that uses a central process to manage the process
ring.


-module(ring).
-export([start/3, manager/0, loop/1]).


start(M, N, Message) ->
register(manager, spawn(ring, manager, [])),
io:format("Manager is ~w~n", [manager]),
manager!{create, N},
manager!{send, M, Message},
manager!{stop},
ok.


manager() ->
%This process manages ring processes
receive
{create, N} ->
PList = create(N, []), %Create the processes list
[First|_] = PList, %Pickup the first one
setup(First, PList), %Setup the ring
register (ring, First), %Identify the ring by the first Process
manager();
{send, M, Message} -> %When receiving messages
send(ring, M, Message), %send them to the ring
manager();
{stop} -> %When receiving stop
ring!{stop, self()} %stop the ring
end.

create(0, PList) -> PList;
create(N, PList) ->
create(N-1, [spawn(ring, loop, [[]])|PList]).

setup(First, [Head|[]]) ->
Head!{setNext, First}; %Link the last process to the first
setup(First, [Head|PList]) ->
[Next|_] = PList,
Head!{setNext, Next},
setup(First, PList).


send(_, 0, _) -> ok;
send(First, M, Message) ->
First!{message, self(), Message},
send(First, M-1, Message).

loop(Next) ->
receive
{setNext, NextPid} ->
io:format("~w linked to ~w~n",[self(), NextPid]),
loop([NextPid|Next]);
{message, Pid, Message} ->
io:format("~w received message from ~w: ~w~n", [self(), Pid,
Message]),
[NextPid|_] = Next,
NextPid!{message, self(), Message},
loop(Next);
{stop, Pid} ->
io:format("~w received stop message from ~w~n", [self(), Pid]),
[NextPid|_] = Next,
NextPid!{stop, self()}
end.

it needs some tweaking so feel free to send any comment.
Regards.
Sami Bouafif.

Sami

unread,
Jan 4, 2010, 5:10:48 PM1/4/10
to Erlang Programming
hi,

Below a solution where a central process sets up the ring and manage
it.

-module(ring).
-export([start/3, manager/0, loop/1]).


start(M, N, Message) ->


It need some tweaking, so feel free to send any critic.

Regards,
Sami.

Reply all
Reply to author
Forward
0 new messages