Erlang で Process の Join

  • 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を関数呼び出しの度に引き回す必要もなく、グローバルにアクセスできるアトムを紐付けておくことができるので使い勝手が良い