2017-08-09 6 views
3

register(atom, spawn..)を使用して新しく生成されたプロセスを登録する場合、またはPid = spawn..を使用すると違いがありますか?Erlang:プロセスの登録と変数へのPidの割り当ての違い

てみましょう最初にする単純なサーバーループ:

-module(geometry_server). 
-export([loop/0]). 

loop() -> 
    receive 
     {Client, {square, S} = Tuple} -> 
      io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]), 
      Client ! {self(), Tuple, S*S}, 
      loop() 
    end. 

今クライアント:

-module(geometry_client). 
-export([client/2, start_server/0]). 

client(Pid_server, Geom_tuple) -> 
    Pid_server ! {self(), Geom_tuple}, 
    receive 
     {Pid_server, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and  server was ~p~n", [Geom_tuple, Area, Pid_server]) 

    after 1000 -> 
      io:format("~p~n",["received nothing from server"]) 
    end. 

start_server() -> spawn(geometry_server, loop, []). 

例を取るために、私はプログラミングErlangの本からの古いプログラムでこれをやりました

両方をコンパイルした後、実行します。

​​

その後、私はそれらを呼び出すと、次のような結果を得る:私は登録した原子を使用する場合

5> geometry_client:client(Q, {square,2}). 
Server: Area of square of Side 2 is 4 and Client was <0.60.0> 
Client: Area of {square,2} is 4 and server was <0.77.0> 
ok 
6> geometry_client:client(q, {square,2}). 
Server: Area of square of Side 2 is 4 and Client was <0.60.0> 
"received nothing from server" 
ok 

なぜクライアントがサーバから何も受信しません?サーバーは明らかにクライアントからメッセージを受信しました。

私は

7> geometry_client:client(whereis(q), {square,2}). 
Client: Area of {square,2} is 4 and server was <0.77.0> 
Server: Area of square of Side 2 is 4 and Client was <0.60.0> 
ok 
12> 

を行う場合は、上記した後、だから私は、メールボックスがすでに理由で前のコマンドからのサーバーからのメッセージを持っていると結論付けているので、私は、サーバーがメッセージを送っていることを確認することができますサーバーのメッセージを受信して​​印刷する前に、クライアントの出力が印刷されます。

何が欠けていますか?なぜ私は登録された原子を使用すると、メッセージを受信する問題はありますか?

答えて

4

client/2ファンクションのreceiveは、{Pid_server, Geom_tuple, Area}に一致するメッセージを待機します。 qを引数として渡した場合、Pid_serverqですが、サーバがをクライアントに返すメッセージは、最初の要素がサーバの実際のPIDであり、名前ではなく、サーバの実際のPIDとなるタプルです。receiveが終わることを意味しますafterブロックにあります。

これを解決する方法はたくさんあります。 client/2を変更してwhereis/1を使用すると、登録済みのプロセスのPIDを取得し、Pid_serverがアトムの場合はreceiveに使用できます。

ここでの参考文献を使用するのが最善の方法です(make_ref/0参照)。サーバーにメッセージを送信するときに参照を作成すると、サーバーはそれを応答で戻します。 make_ref/0によって返されたすべての参照が一意であることが保証されているため、この方法では、送信したリクエストに対する応答を受け取ることが保証されます。 client/2

は、実行します。

client(Pid_server, Geom_tuple) -> 
    Ref = make_ref(), 
    Pid_server ! {Ref, self(), Geom_tuple}, 
    receive 
     {Ref, Geom_tuple, Area} -> io:format("Client: Area of ~p is ~p and  server was ~p~n", [Geom_tuple, Area, Pid_server]) 
    after 1000 -> 
      io:format("~p~n",["received nothing from server"]) 
    end. 

およびサーバーで:

loop() -> 
    receive 
     {Ref, Client, {square, S} = Tuple} -> 
      io:format("Server: Area of square of Side ~p is ~p and Client was ~p~n", [S, S*S, Client]), 
      Client ! {Ref, Tuple, S*S}, 
      loop() 
    end. 
関連する問題