2017-08-09 4 views
3

Est-ce que cela fait une différence si j'inscris un processus nouvellement généré en utilisant register(atom, spawn..) ou si je le fais Pid = spawn..?Erlang: différence entre le processus d'enregistrement et l'assignation de Pid à la variable

Pour prendre un exemple, je viens de faire cela avec un vieux programme de la programmation livre Erlang:

d'abord faire une simple boucle de serveur Let:

-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. 

maintenant un client:

-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, []). 

Après avoir compilé les deux, je

register(q, Q = geometry_client:start_server()). 

Je les appelle et obtenir des résultats comme suit:

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 

Pourquoi le client reçoit rien du serveur lorsque j'utilise l'atome enregistré ?? Le serveur a évidemment reçu le message du client.

Je peux confirmer que le serveur a envoyé un message, car après ce qui précède, si je

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> 

Je conclus donc que la boîte aux lettres a déjà le message du serveur de la commande précédente, ce qui explique pourquoi la La sortie du client est imprimée avant que le message du serveur ne soit reçu et imprimé ...

Qu'est-ce que je manque? Pourquoi y a-t-il un problème à recevoir le message lorsque j'utilise l'atome enregistré?

Répondre

4

La fonction receive de votre fonction client/2 attend un message correspondant à {Pid_server, Geom_tuple, Area}. Lorsque vous passez q comme argument, Pid_server est q, mais le message que le serveur envoie retour au client est un tuple avec le premier élément étant toujours le PID réel du serveur, pas son nom, ce qui signifie que votre finit dans le bloc after.

Il existe plusieurs façons de résoudre ce problème. Vous pouvez modifier client/2 pour utiliser whereis/1 pour obtenir le PID du processus enregistré et l'utiliser dans receive si Pid_server est un atome.

Le meilleur moyen serait d'utiliser des références ici (voir make_ref/0). Vous créez une référence lors de l'envoi d'un message au serveur et le serveur le renvoie dans la réponse. De cette façon, vous êtes assuré de recevoir la réponse à la demande que vous venez d'envoyer, car chaque référence renvoyée par make_ref/0 est garantie unique.

En client/2, faites:

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. 

Et dans le serveur:

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.