Erlang trong>
这种行为是正常的,让我们简单地看一下Erlang内存模型。Erlang进程内存分为三个主要部分: 过程控制块(PCB): 它保存进程pid、注册名称、表、状态和指向其队列中消息的指针 堆栈: 它保存函数参数、局部变量和函数返回地址 私有堆:它保存传入的消息复合数据,如元组、列表和二进制(不大于64字节) 这些内存中的所有数据都属于所属进程,并且是该进程的私有数据 第1阶段: 当调用Erlang trong>,erlang,Erlang,这种行为是正常的,让我们简单地看一下Erlang内存模型。Erlang进程内存分为三个主要部分: 过程控制块(PCB): 它保存进程pid、注册名称、表、状态和指向其队列中消息的指针 堆栈: 它保存函数参数、局部变量和函数返回地址 私有堆:它保存传入的消息复合数据,如元组、列表和二进制(不大于64字节) 这些内存中的所有数据都属于所属进程,并且是该进程的私有数据 第1阶段: 当调用Pid=spawn(mytest,display,[“Hello”])时,将创建服务器进程,然后调用作为参数传递“H
Pid=spawn(mytest,display,[“Hello”])
时,将创建服务器进程,然后调用作为参数传递“Hello”的display函数。由于display/1
是在服务进程中执行的,因此“Hello”
参数存在于服务器的进程堆栈中。继续执行display/1
,直到到达receive
子句,然后阻止并等待与您的格式匹配的消息
第二阶段:
现在P1启动,它执行ServerPid!{调用“Walter”}
,然后执行ServerPid!{呼叫“Dave”}
。在这两种情况下,erlang都会制作消息的副本并将其发送到服务器的进程邮箱(专用堆)。邮箱中复制的此邮件属于服务器进程,而不是客户端进程。
现在,当{call,“Walter”}
匹配时,Msg
绑定到“Walter”
。
从stage1,我们知道Val
被绑定到“Hello”
,Newval
,然后被绑定到“Val++”“Msg”=“Hello Walter”
此时,P2的消息,{call,“Dave”}
仍在服务器邮箱中,等待下一个receive
子句,该子句将在下一次递归调用display/1
时发生NextVal
绑定到NewVal
并使用“Hello Walter”
作为参数传递递归调用dispaly/1
。这将产生第一个打印文件“Hello Walter”,它现在也存在于服务器的进程堆栈中
现在,当再次到达receive
子句时,P2的消息{call,“Dave”}
被匹配。
现在NewVal
和NextVal
绑定到“Hello Walter”+++“+”Dave”=“Hello Dave Walter”。
将此作为参数传递给display/1
作为新的Val
打印Hello Walter Dave
。简而言之,此变量在每个服务器循环上都会更新。它的作用与行为中的状态
术语相同。在您的情况下,连续的客户端调用只是将消息附加到此服务状态变量。现在谈谈你的问题
是否有任何方法可以锁定Val
,因此当我们添加“Walter”
,“Dave”
将等待值设置完成
否。不是通过锁定来进行的。Erlang不是这样工作的。
没有进程锁定构造,因为它不需要。 数据(变量)始终是不可变的,并且对于创建它的进程来说是私有的(,但留在共享堆中的大型二进制文件除外)。 而且,它不是您在
Pid中使用的实际消息!Msg
接收进程正在处理的构造。是的,是的。display/1
函数中的Val
参数是私有的,属于服务器进程,因为它位于堆栈内存中,因为对display/1
的每次调用都是由服务器进程本身进行的。因此,任何其他进程都无法锁定,甚至无法看到该变量
是的。通过顺序消息处理
这正是服务器进程正在做的事情。从it队列中一次轮询一条消息。当
{call,“Walter”}
被拍下时,{call,“Dave”}
正在排队等候。看到意外问候语的原因是,您更改了服务器状态,display/1
参数用于下一个display/1
调用哪个进程{call,“Dave”}
一个进程一次只能处理一条消息。消息按顺序处理,而不是并发处理。这不应该发生。你能发布完整的代码来重现这种行为吗?这可能是客户端的问题。是否有任何callDisplay
进程发出错误,例如超时?一个进程一次只能处理一条消息。消息按顺序处理,而不是并发处理。这不应该发生。你能发布完整的代码来重现这种行为吗?这可能是客户端的问题。是否有任何callDisplay
进程发出错误,例如超时?
%%%-------------------------------------------------------------------
-module(mytest).
%% API
-export([start_link/0,display/1,callDisplay/2]).
start_link()->
Pid=spawn(mytest,display,["Hello"]),
Pid.
display(Val) ->
io:format("It started: ~p",[Val]),
NextVal=
receive
{call,Msg}->
NewVal=Val++" "++Msg++" ",
NewVal;
stop->
true
end,
display(NextVal).
callDisplay(Pid,Val)->
Pid!{call,Val}.
Pid=mytest:start_link().
P1=spawn(mytest,callDisplay,[Pid,"Walter"]),
P2=spawn(mytest,callDisplay,[Pid,"Dave"]).