- Erlang(BEAM)のProcessは、他言語でThread.Joinのようなスレッド・プロセスの終了を待つ機能が無さそうなので、Receiveを用いたメッセージパッシングで実装した
- 今回は、Preforkモデルのように予めProcessをワーカースレッド的に起動しておく実装ではなく、軽量なグリーンスレッドを活用して必要なパラメータが用意できた時点で次々にProcessをSpawnしていく実装を用いている
- 計算すべきパラメータが尽きた時点でプログラムが終了してしまう可能性があるため、起動したProcessが完了したうえでプログラムが終了することを保証するためにJoinが必要になる
process_wait(Num,LastPid) ->
receive
{add, _} -> process_wait(Num+1,LastPid);
{done,_} when Num == 1 ->
case LastPid of
{true,Pid} -> Pid ! {complete,self()};
{false,_} -> process_wait(Num-1,LastPid)
end;
{done,_} -> process_wait(Num-1,LastPid);
{join,Pid} when Num == 0 -> Pid ! {complete,self()};
{join,Pid} -> process_wait(Num,{true,Pid})
end.
- プロセスの状態を管理する
process_wait
に対して、Processの起動直前にaddを送信、Processの終了時点でdoneを送信、プログラムの終了時点でjoinを送信してreceiveで返信を待機、という三種類のメソッドをアトムで実現するように、送信されるメッセージに対してガードを定義する
- LastPidタプルに格納されるPidはtrueの場合のみ取り出して使用することにし、その用途は
complete
を返信することでreceiveによるJoinを完了させる(これによって動き出す)
join
を送信したときに初めてLastPidにPidを登録してそのフラグをtrue
に設定することによって、最後にProcessが終了した際に、join
を送信したプロセスに対してメッセージを送ることができる
complete
の返信は、Num==0
になるタイミング、かつ、一度でもjoin
を受けた後、という条件でなければ発動しない
register
を使えばSpawnしたProcessのPidを関数呼び出しの度に引き回す必要もなく、グローバルにアクセスできるアトムを紐付けておくことができるので使い勝手が良い