Erlang并发理解

Erlang concurrency understanding

最近我一直在尝试了解 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。服务器的增量操作在执行增量之前回复调用者,但这无关紧要,因为在发送回复和实际增量之间没有处理任何消息。每条读取的消息都会产生一个回复,其中包含在它之前到达的所有增量消息的效果。由于保证从一个进程到另一个进程的消息顺序,任何递增然后读取的进程都保证至少读取它自己的增量。服务器的读操作简单地用当前循环值回复。重置操作未使用。

Child1 递增,然后阅读。它最初与 Parent 并发运行,然后与 Child2 并发运行,两者都递增。因此它可以只从它自己的增量中读取 1,从它自己的增量和它的父增量中读取 2,或者如果它的读取也从 Child2 中获取增量,则为 3。

Child2 也递增,然后读取,但直到 Parent 已经递增后才开始。因此,它可以读取的最小值是 2,并且由于它与 Child1 同时运行,因此它也可以读取 3。

父级递增,然后读取,因此它可以读取的最小值是 1。它的读取与 Child1 和 Child2 同时运行,因此如果它的读取发生在它们的任何一个递增之前,它会看到一个 1。它也可以读取一个如果它的读取拾取了其中一个子增量,则为 2;如果它的读取拾取了两个子增量,则为 3。