Erlang trong>

Erlang trong>,erlang,Erlang,这种行为是正常的,让我们简单地看一下Erlang内存模型。Erlang进程内存分为三个主要部分: 过程控制块(PCB): 它保存进程pid、注册名称、表、状态和指向其队列中消息的指针 堆栈: 它保存函数参数、局部变量和函数返回地址 私有堆:它保存传入的消息复合数据,如元组、列表和二进制(不大于64字节) 这些内存中的所有数据都属于所属进程,并且是该进程的私有数据 第1阶段: 当调用Pid=spawn(mytest,display,[“Hello”])时,将创建服务器进程,然后调用作为参数传递“H

这种行为是正常的,让我们简单地看一下Erlang内存模型。Erlang进程内存分为三个主要部分:

过程控制块(PCB): 它保存进程pid、注册名称、表、状态和指向其队列中消息的指针

堆栈: 它保存函数参数、局部变量和函数返回地址

私有堆:它保存传入的消息复合数据,如元组、列表和二进制(不大于64字节)

这些内存中的所有数据都属于所属进程,并且是该进程的私有数据

第1阶段:

当调用
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"]).