複数プロセスへのブロードキャストってどうしたらいいんだ?

普通、Erlangのメッセージは

プロセスID ! メッセージの項

という形で、プロセスのIDを特定しないといけない。まぁ、プロセスのIDのリストを持っておけばいいという話なのだろうけど、

broadcast(Message, [Pid| [ ] ]) -> Pid ! Message;
broadcast(Message, [Pid| TailofList ]) -> 
     Pid ! Message,
     broadcast(Message, TailofList).

という他にやりようはないのか?とか、つらつら考えたメモ(以下、文法チェックもろくにしてないメモなので、決して信用しないでください。随時修正、削除されることがあります。)

プロセスの集合にブロードキャストする場合、linkして、生き死にで伝えるという荒業が考えられる

親プロセスを殺すわけにはいかないので、都合の良い親戚プロセスをでっち上げてリンクしておき、子プロセスの集団ではしっかりcatchしておく。と。
で、一回ブロードキャストしたら、次の「叔父さん」をspawnして、そのPidでリンクさせる、と。
このあたりは「プログラミングErlang」の9章にくわしい。p.127-

子プロセスの集団に単純に死んで欲しいだけなら

以下、思いつきで書いただけのコードで、動作するかどうかテストしてません。

set_dynamite([H | [ ] ]) ->
    link(H);
set_dynamite([H|L]) ->
    link(H).

Jibaku_Pid = spawn(fun() -> set_dynamite([Pid1, Pid2, Pid3]) end).
exit(Jibaku_Pid, kill).

こうすると、Jibaku_Pid は無条件に殺され、Jibaku_Pidにlinkされた3つのプロセスPid1,Pid2, Pid3は{'EXIT', Jibaku_Pid, killed}のメッセージを受け取る。

仕事してもらうためのブロードキャスト通知ならば

上記のコードでは、普通はこれでプロセスPid1, Pid2, Pid3は死んでしまう。死ぬんではなくて、なんらかの処理をしてほしいならば、シグナルを受け取る側で終了シグナルをトラップしておく必要がある。

%% 子プロセスでのシグナルキャッチ
%%
survive(Parent) ->
    receive
        {'EXIT', _Pid, Why} ->
        %%ここで何か仕事をする。内容はWhyに依存する。たとえば、親プロセスに返事をするとか
        Parent ! {hi},
        survive(Parent)
    end.

set_dynamite([H | [ ] ]) ->
    link(H);
set_dynamite([H|L]) ->
    link(H),
    set_dynamite(L).

do_broadcast(Why, PidList) ->
    Jibaku_Pid = spawn(fun() -> set_dynamite(PidList) end),
    exit(Jibaku_Pid, Why).

使い方はこんな感じか?

> Pid_A = spawn(fun() -> survive(self()) end).
> Pid_B = spawn(fun() -> survive(self()) end).
> Pid_C = spawn(fun() -> survive(self()) end).
> do_broadcast(sendmeindex, [Pid_A, Pid_B, Pid_C]). 
> do_broadcast(kill, [Pid_A, Pid_B, Pid_C]). 

最後のやつで本当にみんな死ぬかなぁ?
というわけでこれからテストしてみる俺(ぉ

他のやり方:プロセスをリストにして生成しておく

伝言ゲームしてもらう機能を最初から埋め込んでおく。

to_next(Prev_Pid, [H | [ ] ] ) ->
    loop(Prev_Pid, H);
to_next(Prev_Pid, [H | T] = _FunctionList ) ->
    Next_Pid = spawn(fun() -> to_next(self(), T),
    loop(Prev_Pid, Next_Pid, H).


loop(Prev_Pid, F) ->
    receive
        {Prev_Pid, Something} -> 
            F(Something),
            loop(Prev_Pid, Next_Pid, F)
    end.

loop(Prev_Pid, Next_Pid, F) ->
    receive
        {Prev_Pid, Something} -> 
            Next_Pid ! F(Something),
            loop(Prev_Pid, Next_Pid, F)
    end.

実行するとしたら、こんな感じ?

> Pid = spawn(fun() -> to_next(self(), [Func_1, Func_2, Func_3, Func_4]) end).
> Pid ! "manupulate me"
> receive
      {Pid, Responce} ->
          io:format("Pid: ~p Response: ~p~n", [Pid, Response])
  end
  :繰り返し、、、