オライリーの『Erlangプログラミング』
そのエクササイズの4-2を解いてみました。
内容
課題はN個のプロセスがリング上に形成されていて、
メッセージをM個伝達し、
M個伝達し終わったらプロセスを終了するというものです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-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. |
実行結果は下の通り。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 件のコメント:
コメントを投稿