Newbie question can't explain behaviour of my program (tutorial exercise masterslave)
Folkert Hendrix
fjmhendrix@REDACTED
Mon Jun 22 14:29:53 CEST 2009
Hi,
I did the tutorial exercise Master Slave
(http://erlang.org/course/exercises.html#ms ) and it does work, but i
can't explain it's behaviour. Is my code wrong?:
this is the output i get:
(erlide@REDACTED)6> masterslave:start(5).
Slave: 5 with Pid: <0.97.0> created
true
Slave: 4 with Pid: <0.98.0> created
Slave: 3 with Pid: <0.99.0> created
(erlide@REDACTED)7> masterslave:to_slave(hello,2).
Slave: 2 with Pid: <0.101.0> created
Slave: 1 with Pid: <0.106.0> created
Slave 2 recieved the message: hello
{message_to_slave,{hello,2}}
(erlide@REDACTED)8> masterslave:to_slave(die,1).
{message_to_slave,{die,1}}
Slave 1 with old PID <0.106.0> restarted with new Pid: <0.108.0>
(erlide@REDACTED)9> masterslave:stop().
Master going downstop
(erlide@REDACTED)10>
Questions:
In the process view of toolbar:start(). I only see 4 slaves created.
When i give the command masterslave:to_slave(hello,2) then the rest of
the slaves are created and can i see the registered master. Slave 2
responds but it wasn't created yet?
When the master stop, the slaves also stop, but i expected the slave
received the exit signal and should write a message.
the code:
%% Author: fh
%% Created: Jun 19, 2009
%% Description: TODO: Add description to masterslave
-module(masterslave).
%%
%% Include files
%%
-include_lib("eunit/include/eunit.hrl").
%%
%% Exported Functions
%%
-export([start/1, stop/0, to_slave/2, init/1, loop_master/1, loop_slave/0]).
%%
%% API Functions
%%
%% Start the master and tell it to start N slave processes.
%% Register the master as the registered process master.
start(N) ->
register(master, spawn(?MODULE, init, [N]) ).
%%The slave should print all messages it recieves except the message die
loop_slave() ->
receive
{master, {say, {Msg, N}}} ->
io:format("Slave ~w recieved the message: ~w~n",[N, Msg]),
loop_slave();
{master, die} ->
exit("Slave Died");
{'EXIT', master, _Reason} ->
io:format("Slave exit normal"),
exit(normal)
end.
%%
%% Interface functions
%%
%% Send a message to the master and tell it to relay the message to slave N.
%% The slave should exit (and be restarted by the master) if the message is die.
to_slave(Message, N) ->
master ! {message_to_slave, {Message, N}}.
stop() ->
master ! stop.
%%
%% Local Functions
%%
init(N) ->
process_flag(trap_exit, true),
init_slave(N, []).
init_slave(0, Slaves) ->
loop_master(Slaves);
init_slave(N, Slaves) ->
Pid = spawn_link(?MODULE, loop_slave, []),
io:format("Slave: ~w with Pid: ~w created~n",[N, Pid]),
init_slave(N-1,[{N,Pid} | Slaves]).
restart_slave(Pid, Slaves) ->
{N, OldPid } = lists:keyfind(Pid,2,Slaves),
NewPid = spawn_link(?MODULE, loop_slave, []),
io:format("Slave ~w with old PID ~w restarted with new Pid:
~w~n",[N, OldPid, NewPid]),
lists:keyreplace(Pid, 2, Slaves, {N, NewPid}).
%% return slave N
master_to_slave(Slaves, N, Msg) ->
case lists:keyfind(N,1,Slaves) of
false -> io:format("Slave ~w doesn't excist!",[N]);
{_N, Pid} -> Pid ! {master, Msg}
end.
%% handle messages from slaves
%% The master should detect the fact that a slave processe died,
%% restart it and print a message that it has done so.
loop_master(Slaves) ->
receive
{message_to_slave, {Message, N}} when Message == die ->
master_to_slave(Slaves,N, die),
loop_master(Slaves);
{message_to_slave, {Message, N}} ->
master_to_slave(Slaves,N, {say, {Message, N}}),
loop_master(Slaves);
stop ->
io:format("Master going down"),
exit("Master stopped");
{'EXIT', Pid, Reason} ->
NewSlaves= restart_slave(Pid, Slaves),
loop_master(NewSlaves);
Other ->
error_logger:error_msg( "Error: Process ~w got unknown
msg ~w~n.", [self(), Other]),
loop_master(Slaves)
end.
Regards,
Folkert
More information about the erlang-questions
mailing list