[erlang-questions] Question regarding problems in Joe's book

David Stokar <>
Fri Aug 10 17:11:45 CEST 2007


Agreeing to Toby (
http://www.erlang.org/pipermail/erlang-questions/2007-July/028133.html) I
got the following:

-module(conc_problems).
-export([start/2,start_server/0]).

%%    2> c(conc_problems).
%%    {ok,conc_problems}
%%    3> conc_problems:start_server().    This starts the registration
server (A singleton)
%%    true
%%    4> conc_problems:start(foo2, fun area_server1:loop/0).  This calls the
registration method on the above singleton server
%%    Received:{foo2,#Fun<area_server1.loop.0>}
%%    Undef:foo2
%%    {foo2,#Fun<area_server1.loop.0>,{success,<0.46.0>}}
%%    5> conc_problems:start(foo2, fun area_server1:loop/0).
%%    Received:{foo2,#Fun<area_server1.loop.0>}
%%    Def: <0.46.0>:{foo2,#Fun<area_server1.loop.0>}
%%    {foo2,#Fun<area_server1.loop.0>,{fail,<0.46.0>}}
%%    6> foo2 ! {self(),{circle, 9}}.
%%    {<0.31.0>,{circle,9}}Server: Area of circle is 254.469


%% start/2
%%    start(AnAtom, Fun) to register AnAtom as spawn(Fun).
%%    Make sure your program works correctly in the case when two
%%    parallel processes simultaneously evaluate start/2. In this case,
%%    you must guarantee that one of these processes succeeds and the
%%    other fails.
start(AnAtom,Fun) ->
    rpc(starter, {AnAtom,Fun}).

%% start_server()
%%        Starts the server loop and registers
%%        the process as starter
start_server() ->
    register(starter,spawn(fun() -> loop([]) end)).

%% rpc(Pid, Request)
%%        Forwards Request to Server Pid
%%        Makes process wait for Response from Server
rpc(Pid, Request) ->
    Pid ! {self(), Request},
    receive
        {Pid, Response} ->
            Response
    after 3000 ->
        io:format("Rpc timed out")
    end.

%% start_fun
%%         Starts fun Fun and registers
%%        it as AnAtom if undefined
%%        Returns:
%%            {success, PID} if undefined
%%            {fail, PID} if allready registered
start_fun(undefined,{AnAtom,Fun}) ->
    io:format("Undef:~p~n" ,[AnAtom]),
    PID = spawn(Fun),
    register(AnAtom,PID),
    {success,PID};
start_fun(PID,X) ->
    io:format("Def: ~p:~p~n", [PID,X]),
    {fail,PID}.

%% loop(x)
%%        Processes messages send to the server
%%        Prints the message out
loop(X) ->
    receive
        {Pid, {AnAtom, Fun}} ->
            io:format("Received:~p~n" ,[{AnAtom, Fun}]),
            REG = whereis(AnAtom),
            Status = start_fun(REG, {AnAtom,Fun}),
            %% self() has to be replaced by starter
            %% because self() == starter evaluates to false
            %% rpc waits for {starter, Response}
            Pid ! {starter,{AnAtom, Fun, Status}},
            loop(X)
    end.



The circle: (Without timer)
-module(conc_problems_ring).
-compile(export_all).

%% start_ring(N,M, Mesg)
%%    N number of processes in Ring
%%    M number of roundings
%%    Mesg the message to transport
start_ring(N,M,Mesg) ->
    [Head|Pids] = [ start() || _ <- lists:seq(1,N)],
    Head ! {self(), {Pids, [], M}, Mesg}.

%% start()
%%        Starts the server loop
start() -> spawn(fun() -> loop([]) end).

%% rpc(Pid, Request)
%%        Forwards Request to Server Pid
%%        Makes process wait for Response from Server
rpc(Pid, Request) ->
    Pid ! {self(), Request},
    receive
        {Pid, Response} ->
            Response
    end.

%% loop(x)
%%        Processes messages send to the server
%%        Prints the message out
loop(X) ->
    receive
        {_, {Pids,VisitedPids,Rounds}, Message} ->
            io:format("~nReceived: ~p Pid: ~p Round: ~p~n" ,[Message,
self(), Rounds]),
            {TagNP, {NPs, NVPs, NRounds}} = next_pid(Pids, VisitedPids,
Rounds),
            case {TagNP, NRounds} of
                {last,_} ->
                    io:format("  finished last~n"),
                    true;
                {NP,0}    ->
                    io:format("  finished~n"),
                    NP ! {self(), {NPs, NVPs, NRounds}, Message},
                    true;
                {NP,_}    ->
                    io:format("  pass on~n"),
                    NP ! {self(), {NPs, NVPs, NRounds}, Message},

                    loop(X)
            end
    end.

%% next_pid(NextPids, PassedPids, Rounds)
%%    Returns the next Pid out of the NextPids list
%%    If NextPids is empty, we finished a round
%%    and decrease the value of Rounds.
%%    We can then restart by taking PassedPids as next Pids
next_pid([],_,0) -> {last,{[],[],[]}};
next_pid([],[NP|R],M) -> {NP,{R,[self()],M-1}};
next_pid([NP|R],X,M) -> {NP,{R,[self()|X],M}}.


Session:
1> c(conc_problems_ring).
{ok,conc_problems_ring}
2> conc_problems_ring:start_ring(3,2,"Hi").
{<0.31.0>,{[<0.39.0>,<0.40.0>],[],2},"Hi"}
Received: "Hi" Pid: < 0.38.0> Round: 2

  pass on

Received: "Hi" Pid: <0.39.0> Round: 2
  pass on

Received: "Hi" Pid: <0.40.0> Round: 2
  pass on

Received: "Hi" Pid: < 0.39.0> Round: 1
  pass on

Received: "Hi" Pid: <0.38.0> Round: 1
  finished

Received: "Hi" Pid: <0.39.0> Round: 0
  finished

Received: "Hi" Pid: < 0.40.0> Round: 0
  finished last
3>


Enjoy David Stokar
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20070810/65ab917c/attachment.html>


More information about the erlang-questions mailing list