Monday, May 24, 2010

Erlang Process Ring!

I though I might just post this. This is a couple of weeks old. It's the exercise from chapter four, regarding the erlang rings.


-module(ring).
-import(erlang, [error/1]).
-export([start/2]).
-export([init/0]).

-ifdef(debug).
-define(DBG(Str, Args), io:format(Str, Args).
-else.
-define(DBG(Str, Args), ok).
-endif.

%% Process that makes the ring
loop(Pid, Id) ->
receive
{stop, FromPid} ->
?DBG("~p received msg: stop from ~p\n", [self(), FromPid]);
{Msg, FromPid} ->
?DBG("~p received msg: ~p from ~p\n", [self(), Msg, FromPid]),
case Id of
first ->
case Msg of
{_, 0} ->
Pid ! {stop, self()};
{Str, Num} ->
Pid ! {{Str, Num - 1}, self()},
loop(Pid, Id)
end;

middle ->
Pid ! {Msg, self()},
loop(Pid, Id)
end;

Msg ->
io:format("wtf: ~p\n", [Msg]),
error("bad message")
end.


init() ->
receive
{next, Pid, _} ->
?DBG("~p sends to ~p\n", [self(), Pid]),
loop(Pid, middle);
{first, Pid, Num} ->
?DBG("[first:~p] sends to ~p\n", [self(), Pid]),
Pid ! {{"hello", Num}, self()},
loop(Pid, first);
Msg ->
io:format("wtf: ~p\n", [Msg]),
error("bad init message")
end,
ok.

%% To set up the ring
create_procs(0, PidList) ->
PidList;
create_procs(N, PidList) ->
Pid = spawn(?MODULE, init, []),
NewPidList = [Pid|PidList],
create_procs(N - 1, NewPidList).

set_up_ring_(Num, Last, [Pid|[First|[]]]) -> %% Num is the number of messages
Last ! {next, First, Num},
?DBG("~p <- ~p\n", [Last, First]),
First ! {first, Pid, Num},
?DBG("~p <- ~p\n", [First, Pid]);
set_up_ring_(Num, Last, [Pid1|[Pid2|PidList]]) ->
Pid2 ! {next, Pid1, Num},
?DBG("~p <- ~p\n", [Pid2, Pid1]),
set_up_ring_(Num, Last, [Pid2|PidList]).

set_up_ring(Num, [X|[Y|XS]]) ->
set_up_ring_(Num, X, [X|[Y|XS]]);
set_up_ring(_, _) ->
error(badarg).

start(NumProcs, NumMessages) when (NumProcs >= 2) and (NumMessages >= 1) ->
PidList = create_procs(NumProcs, []),
set_up_ring(NumMessages, PidList).

No comments:

Post a Comment