最近我一直试图了解Erlang中的并发服务器。请考虑以下向服务器发出请求的代码。取决于 特定的执行顺序,3个过程可以打印不同的值。什么是订单以及每个流程的最高和最低价值是什么?
test() ->
Server = start(),
spawn(fun() ->
incr(Server),
io:format("Child 1 read ~p~n", [read(Server)]) end),
incr(Server),
spawn(fun() ->
incr(Server),
io:format("Child 2 read ~p~n", [read(Server)]) end),
io:format("Parent read ~p~n", [read(Server)]).
代码针对以下服务器运行:
-module(p4).
-export([start/0, init/0, read/1, incr/1, reset/1]).
start() ->
spawn(fun() -> init() end).
init() -> loop(0).
loop(N) ->
receive
{read, Pid} ->
Pid ! {value, self(), N},
loop(N);
{incr, Pid} ->
Pid ! {incr_reply, self()},
loop(N+1);
{reset, Pid} ->
Pid ! {reset_reply, self()},
loop(0)
end.
read(Serv) ->
Serv ! {read, self()},
receive {value, Serv, N} -> N end.
incr(Serv) ->
Serv ! {incr, self()},
receive {incr_reply, Serv} -> ok end.
reset(Serv) ->
Serv ! {reset, self()},
receive {reset_reply, Serv} -> ok end.
我不完全确定订单,但我想可能就是这样:
这对于最低,最高值和订单都是正确的吗?
答案 0 :(得分:1)
循环中的初始值为0.服务器的递增操作在执行增量之前回复调用者,但这并不重要,因为在发送该回复和实际增量之间没有处理任何消息。每个读取消息都会产生一个回复,其中包含在其之前到达的所有增量消息的效果。由于保证从一个进程到另一个进程的消息排序,所以任何增加然后读取的进程都保证至少读取它自己的增量。服务器的读操作只是回复当前循环值。重置操作未使用。
Child1递增,然后读取。它最初与Parent同时运行,然后与Child2同时运行,两者也都递增。因此,它可以从它自己的增量中读取1,从它自己的增量中读取2,从它的父节点增加2,如果它的读取也从Child2中获取增量,则读取3。
Child2也会递增,然后读取,但在Parent已经递增之后才会启动。因此,它可以读取的最小值是2,因为它与Child1同时运行,所以它可以读取3。
父递增,然后读取,因此它可以读取的最小值是1.它的读取与Child1和Child2同时运行,因此如果它的读取发生在它们的任何一个增量之前,它会看到1.它可以选择读取2如果它的读取可以选择子项增量,如果读取了两个子项增量,则读取3。