M.Dani
M.Dani

Reputation: 37

Erlang concurrency understanding

Lately I've been trying to understand concurrent servers in Erlang. Consider the following code that makes requests to the server. Depending on the particular order of execution, different values may get printed by the 3 processes. What are the orders and what is the highest and lowest value of each process?

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)]).

The code runs against the server below:

-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.

I'm not completely sure about the orders, but I guess it could be that:

Is this correct for both the lowest, highest values and the orders?

Upvotes: 2

Views: 115

Answers (1)

Steve Vinoski
Steve Vinoski

Reputation: 20014

The initial value in the loop is 0. The server's increment operation replies to the caller before performing the increment, but that doesn't matter because no messages are processed between the sending of that reply and the actual increment. Each read message results in a reply containing the effects of all increment messages that arrived before it. Because of guaranteed message ordering from one process to another, any process that increments then reads is guaranteed to read at least its own increment. The server's read operation simply replies with the current loop value. The reset operation is unused.

Child1 increments, then reads. It runs concurrently with Parent initially and then later with Child2 as well, both of which also increment. It can therefore read 1 from just its own increment, 2 from its own increment and that of its parent, or 3 if its read also picks up the increment from Child2.

Child2 also increments, then reads, but it doesn't start until after the Parent has already incremented. The minimum it can read is therefore 2, and since it runs concurrently with Child1, it could alternatively read a 3.

Parent increments, then reads, so the minimum it can read is 1. Its read runs concurrently with Child1 and Child2, so if its read happens before either of their increments, it sees a 1. It could alternatively read a 2 if its read picks up either of the child increments, or a 3 if its read picks up both child increments.

Upvotes: 1

Related Questions