0
votes

I am new at Erlang, and I have the following homework-problem to solve:

A "control" process has to offer a user function go(N,M) that generates a lists L of M random integer numbers in {1,2,...,M}, sets up ring of N processes (so-called "workers") and sends a token to the first worker. When worker k receives a token, it sends a message {eat, self()} to control and sends the token to next worker.

When control receives a message {eat, Pid}, it withdraws the head H of the list L and appends to a result list the tuple {H, Pid}. When list L is empty, control sends a stop message to the ring that terminates the workers and prints the result list.

Any help would be apreciated

1

1 Answers

3
votes

Actually there were two approaches to solve this problem.
The first one is: The control spawns all the workers in the ring and here is the solution:

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

And the second one is:control spawns only the first worker in the ring. Every new worker in the ring, but the last one, spawns the next worker:

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