有没有办法在Erlang中的不同进程之间锁定变量
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有没有办法在Erlang中的不同进程之间锁定变量相关的知识,希望对你有一定的参考价值。
我的模块中有变量,并且有接收方法来更新变量值。并且多个进程同时调用此方法。我需要在一个进程修改它时锁定此变量。样品如下
mytest.erl
%%%-------------------------------------------------------------------
-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"]).
我希望它可以像“Hello Walter Dave”一样逐一添加“Walter”,“Dave”,然而,当它们中太多的一起运行时,一些名字(Walter,Dave等)将被覆盖。
因为当P1,P2同时启动时,Val都是“Hello”。 P1加“Walter”成为“Hello Walter”,P2加“Dave”成为“Hello Dave”。 P1首先将它保存为NextVal为“Hello Walter”,然后P2将其保存为NextVal为“Hello Dave”,因此结果为“Hello Dave”。 “Hello Walter”被“Hello Dave”取代,“Walter”永远失去了。
有什么方法可以锁定“Val”,所以当我们添加“Walter”时,“Dave”会等到Value设置完成吗?
即使这是一个古老的问题,但值得解释。从你说的话,如果我是正确的,你期待看到
“你好沃尔特”和“你好戴夫”。但是,你看到连续的名字被附加到前者,“Hello Walter Dave ..”
这种行为是正常的,看看让我们简单地看一下Erlang内存模型。 Erlang进程内存分为三个主要部分:
进程控制块(PCB):它保存进程pid,注册名称,表,状态和指向其队列中消息的指针。
Stack:这个保存函数参数,局部变量和函数返回地址。
私有堆:它保存传入的消息复合数据,如元组,列表和二进制(不大于64字节)。
这些存储器中的所有数据都属于拥有进程并且是私有的。
阶段1:
调用Pid=spawn(mytest,display,["Hello"])
时,将创建服务器进程,然后调用以“Hello”作为参数传递的显示函数。由于display/1
在服务进程中执行,因此"Hello"
参数存在于服务器的进程堆栈中。继续执行display/1
,直到它到达receive
子句然后阻止并等待与您的格式匹配的消息。
第二阶段:
现在P1开始,它执行ServerPid ! {call, "Walter"}
,然后P2执行ServerPid ! {call, "Dave"}
。在这两种情况下,erlang都会复制邮件并将其发送到服务器的进程邮箱(Private Heap)。邮箱中复制的邮件属于服务器进程而不是客户端。现在,当{call, "Walter"}
匹配时,Msg
将被绑定到"Walter"
。从第一阶段开始,我们知道Val
受限于"Hello"
,然后Newval
受限于
"Val ++ " " ++ Msg" = "Hello Walter"
。
此时,P2的消息{call, "Dave"}
仍在服务器的邮箱中等待下一个receive
子句,该子句将在下一次递归调用display/1
时发生。 NextVal
被绑定到NewVal
并且dispaly/1
的qinxswpoi的递归调用被作为参数传递。这给出了第一个打印"Hello Walter"
,它现在也存在于服务器的进程堆栈中。
现在当再次到达"Hello Walter "
子句时,P2的消息receive
匹配。现在{call, "Dave"}
和NewVal
绑定到NextVal
这个作为参数传递给"Hello Walter" ++ " " ++ "Dave" = "Hello Walter Dave".
作为新的display/1
打印Val
。简而言之,此变量在每个服务器循环上都会更新。它与Hello Walter Dave
行为中的State
术语具有相同的目的。在您的情况下,连续的客户端调用只是将消息附加到此服务状态变量。现在问你的问题,
有什么方法可以锁定gen_server,所以当我们添加
Val
时,"Walter"
会等到值设置完成吗?
不,不是通过锁定。 Erlang不会这样工作。
没有进程锁定结构,因为它不需要。数据(变量)始终是不可变的和私有的(除了保留在共享堆中的大型二进制文件)到创建它的进程。此外,它不是您在"Dave"
构造中使用的实际消息,它是接收过程的过程。这是复制。 yourPid ! Msg
函数中的Val
参数是私有的,属于服务器进程,因为它存在于堆栈内存中,因为每次调用display/1
都是由服务器进程本身进行的。因此,任何其他进程都无法锁定甚至看不到该变量。
是。通过顺序消息处理这正是服务器进程正在执行的操作。从队列中一次轮询一条消息。当display/1
被采取时,{call, "Walter"}
正在排队等候。您看到意外问候的原因是因为您更改了服务器状态,{call, "Dave"}
参数用于下一个display/1
调用哪个进程display/1
以上是关于有没有办法在Erlang中的不同进程之间锁定变量的主要内容,如果未能解决你的问题,请参考以下文章