@kyanny's blog

My life. Opinions are my own.

プログラミングErlangの第8章に簡単なクライアントサーバを書く例が載っていた。

そのプログラムを改良していく過程で、クライアントがサーバにリクエストを送信したあと、レスポンスを受け取るために receive するコードが、リクエストを送ったサ
ーバ以外のプロセスから送られたメッセージも受け取り得る問題があるので receive するときに送信先サーバの Pid もパターンマッチに含めると良い、というような解説があった。

理屈はわかるのだけど、じゃあそのクライアントがレスポンスを受け取る前に他のプロセスからメッセージを受け取ってしまった場合にどうなるのだろう?と気になってコードを書いて実験してみたかったのだけど、うまくいかない。

これをシェルから、

> c(wait_server).
> Server_Pid = spawn(fun wait_server:server/0).
> wait_server:client(Server_Pid, 30000, {a,b,c}). % 3秒

とするともちろん期待したとおり3秒待ってレスポンスが返るのだけど、

> c(wait_server).
> Server_Pid = spawn(fun wait_server:server/0).
> self(). % このプロセスの Pid を取得
> wait_server:client(Server_Pid, 30000, {a,b,c}). % 30秒

としたあと Ctrl-G -> s -> c 2 とかやって新しいシェルに入り、

> pid(0,30,0) ! {x,y,z}.

などとして、さっきレスポンスを30秒間待っていたクライアントのプロセスにメッセージを送り、元のシェルに戻ると、すでに receive は終わっているようで入力を受け付けるようになってる。けどそのあとしばらく待ってても何もおこらない。ここで30秒経過した場合に、サーバのプロセスが送り返しているはずのレスポンスはどこへいったのか?を確かめたかったのだけど確かめられなかった。

id:cooldaemon さんに Twitter でアドバイスをもらった内容を風呂に入りながら考えていて、クライアントのプロセスも spawn すればシェルが receive で固まることはなくてすぐに入力できるしクライアントプロセスの Pid も変数に束縛できるから実験できそうかな、と思ってやってみたが、

3> Client_Pid = spawn(fun wait_server:client/3(Server_Pid, 30000, {a,b,c})).
received {a,b,c} from <0.37.0>
** exception error: bad argument
     in function  spawn/1
        called as spawn({a,b,c})

きっちり30秒待たされるうえにエラーが出てしまう。 fun ... が返すものは fun ではないので怒られてるんだろうけど、思うようにいかなくて、うーん。 spawn 以上に fun のことが全然わかってないのだろうなぁ。 fun(X) -> X end. という無名関数を作る fun と、 fun Mod:Func/Arity というふうにして関数を参照する fun と、ちゃんと使い分けられないというか、うーん。胸がつかえたような、すっきりしない気分だ。

要するに、上の例でいうと、 receive してないプロセスがメッセージを受け取ったとき送り元のプロセスはどうなるの?単に無視されるだけで何もおこらないの?・・・ということが知りたいのだろうか?何がわからなくて何が知りたいのかすらよくわからないよ。やれやれ。