2013年5月2日木曜日

リング上のプロセスでメッセージを伝達する

Erlang見習中のみけです。

オライリーの『Erlangプログラミング』は各章の最後にエクササイズがあって、

そのエクササイズの4-2を解いてみました。

内容


課題はN個のプロセスがリング上に形成されていて、

メッセージをM個伝達し、

M個伝達し終わったらプロセスを終了するというものです。


-module(ring).
-import(io, [format/2]).
-import(timer, [sleep/1]).
-export([start/3, new_process/3]).
start(M, N, Msg) when M > 0, N > 1 ->
Processes = N - 1,
Size = M - 1,
Count = N * M,
Top = self(),
Pid = spawn(ring, new_process, [Size, Processes - 1, Top]),
format("~p next -> ~p~n", [self(), Pid]),
listen(Size, Processes, Msg, Pid, Count);
start(M, _, _) when M =< 0 ->
{error, "Message size should be larger than 1."};
start(_, N, _) when N =< 1 ->
{error, "The number of processes should be larger than 1."}.
new_process(M, N, Top) ->
Pid = prepare(M, N, Top),
format("~p next -> ~p~n", [self(), Pid]),
listen(M, N, Pid).
prepare(_, 0, Top) -> Top;
prepare(M, N, Top) ->
spawn(ring, new_process, [M, N - 1, Top]).
listen(M, N, Next) ->
receive
{message, Msg, Pid, Count} ->
sleep(10),
print_message(self(), Msg, Pid, M, Count),
Next ! {message, Msg, self(), Count - 1},
case M =:= 0 of
false -> listen(M - 1, N, Next);
true -> ok
end
end.
listen(M, N, Message, Next, Count) ->
Next ! {message, Message, self(), Count},
listen(M, N, Next).
print_message(Pid, Msg, From, M, Count) ->
format("~p => [~p:~p] => ~p", [From, Count, Msg, Pid]),
case M =:= 0 of
true -> format("(final)~n", []);
false -> format("(last : ~p)~n", [M])
end.
view raw ring.erl hosted with ❤ by GitHub



実行結果は下の通り。


1> l(ring).
{module,ring}
2> spawn(ring, start, [3, 7, hello]).
<0.35.0> next -> <0.36.0>
<0.36.0> next -> <0.37.0>
<0.37.0> next -> <0.38.0>
<0.38.0> next -> <0.39.0>
<0.39.0> next -> <0.40.0>
<0.40.0> next -> <0.41.0>
<0.41.0> next -> <0.35.0>
<0.35.0>
<0.35.0> => [21:hello] => <0.36.0>(last : 2)
<0.36.0> => [20:hello] => <0.37.0>(last : 2)
<0.37.0> => [19:hello] => <0.38.0>(last : 2)
<0.38.0> => [18:hello] => <0.39.0>(last : 2)
<0.39.0> => [17:hello] => <0.40.0>(last : 2)
<0.40.0> => [16:hello] => <0.41.0>(last : 2)
<0.41.0> => [15:hello] => <0.35.0>(last : 2)
<0.35.0> => [14:hello] => <0.36.0>(last : 1)
<0.36.0> => [13:hello] => <0.37.0>(last : 1)
<0.37.0> => [12:hello] => <0.38.0>(last : 1)
<0.38.0> => [11:hello] => <0.39.0>(last : 1)
<0.39.0> => [10:hello] => <0.40.0>(last : 1)
<0.40.0> => [9:hello] => <0.41.0>(last : 1)
<0.41.0> => [8:hello] => <0.35.0>(last : 1)
<0.35.0> => [7:hello] => <0.36.0>(final)
<0.36.0> => [6:hello] => <0.37.0>(final)
<0.37.0> => [5:hello] => <0.38.0>(final)
<0.38.0> => [4:hello] => <0.39.0>(final)
<0.39.0> => [3:hello] => <0.40.0>(final)
<0.40.0> => [2:hello] => <0.41.0>(final)
<0.41.0> => [1:hello] => <0.35.0>(final)



なんか、もう少しプログラムの行数を減らせそうな気がする。


やってて覚えたこと


  • atomにプロセスをregister/2関数にて割り当てるとき、既に他のatomにプロセスが割り当てられている場合、エラーが発生する。
    • つまりひとつのプロセスはひとつのatomにしかregister/2関数で割り当てられない
  • whereis/1関数の戻り値はプロセスID
  • プロセスを強制終了する場合は、exit/2関数を用いる。引数はPid、終了する原因(atomなど)

うん


Erlangって型ないですねー

0 件のコメント:

コメントを投稿