Benjamin Halsted // [bgh] todo, add something clever here.

28Apr/100

Erlang Programming Exercise: 4-2

I've finished with the process ring. I've done this exercise once before when reading "Programming Erlang". Last time I had the processes create each other and set up the connections, this time they were created and linked by the start function. The code is much cleaner this time around.

The basic idea is that you create a number of processes and each process knows the process id of it's neighbor in the ring. When a process receives a message, it should forward it on to it's neighbor. You then send X number of messages into the ring and watch your laptop turn into a skillet.

Please review the code and let me know if you have any suggestions.

-module(four_two).

-export([start/3, test/0]).
-export([process_loop/0, process_loop/1]).

test() ->
    FirstPid = start(10,4,"This is a message"),

    %% [bgh] after 15 second, kill it automatically
    receive
    after
	15000 ->
	    stop(FirstPid)
    end.

stop(Pid) ->
    Pid ! {stop, 0}.

start(M, N, Message) ->
    %% [bgh] start N processes
    Pids = lists:reverse(lists:foldl(
				   fun(_Number,PidList) ->
					   NewPid = spawn(?MODULE, process_loop, []),
					   [NewPid|PidList]
				   end,
				   [],
				   lists:seq(1, N)
				 )),

    %% [bgh] Shift the one off the front, and put it on the end
    NeighborPids = rotate_array(Pids),

    %% [bgh] link the N processes together
    link_pids(Pids, NeighborPids),

    [FirstPid|_OtherPids] = Pids,

    %% [bgh] start the message sending by sending M messages to PID
    send_messages_to_pid(M, Message, FirstPid),

    %% [bgh] start the processes sending messages
    FirstPid.

rotate_array([]) ->
    [];
rotate_array([First|_]=List) when length(List) =:= 1 ->
    [First];
rotate_array([First|Remainder]) ->
    io:format("~p ~p~n", [First,Remainder]),
    lists:append(Remainder,[First]).

send_messages_to_pid(M, Message, FirstPid) when M > 0 ->
    FirstPid ! {message, Message},
    send_messages_to_pid(M-1, Message, FirstPid);
send_messages_to_pid(_M, _Message, _FirstPid) ->
    ok.

link_pids([], []) ->
    ok;
link_pids([Pid|Pids], [NPid|NeighborPids]) ->
    Pid ! {link, NPid},
    link_pids(Pids, NeighborPids).

process_loop() ->
    receive
	{link, Pid} ->
	    process_loop({Pid, 0});
	Other ->
	    io:format("Ignored ~p~n", [Other]),
	    process_loop()
    end.

process_loop({Pid, Count}) ->
    receive
	{message, Message} ->
	    Pid ! {message, Message},
	    process_loop({Pid, Count+1});
	{stop, CountSum} ->
	    Pid ! {stop, Count+CountSum},
	    io:format("~p is shutting down, saw ~p messages~n", [self(), Count+CountSum]);
	Other ->
	    io:format("Ignored ~p~n", [Other]),
	    process_loop({Pid, Count})
    end.

Cheers,
Halzy

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit
  • Twitter
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


No trackbacks yet.