I'm trying to understand request order in erlang, but I can't seem to grasp it very well. Here's the example code:
test() ->
Server = start(),
spawn(fun() -> write(Server, 2),
io:format(”Child 1 read ~p~n”, [read(Server)]) end),
write(Server, 3),
write2(Server, 5),
spawn(fun() -> write2(Server, 1),
io:format(”Child 2 read ~p~n”, [read(Server)]) end),
io:format(”Parent read ~p~n”, [read(Server)]).
And here's the server:
start() ->
spawn(fun() -> init() end).
init() -> loop(0).
loop(N) ->
receive
{read, Pid} ->
Pid ! {value, self(), N},
loop(N);
{write, Pid, M} ->
Pid ! {write_reply, self()},
loop(M);
{write2, _Pid, M} -> loop(M)
end.
read(Serv) ->
Serv ! {read, self()},
receive {value, Serv, N} -> N end.
write(Serv, N) ->
Serv ! {write, self(), N},
receive {write_reply, Serv} -> ok end.
write2(Serv, N) ->
Serv ! {write2, self(), N},
ok.
I understand that different values could be printed by the three different processes created in test/0
, but I'm trying to figure out the lowest and highest values that could be printed by those Parent
, Child1
and Child2
processes. The answer states:
Parent
: lowest 1, highest 5Child1
: lowest 1, highest 5Child2
: lowest 1, highest 2
Can somebody explain this?
Keep in mind that Erlang guarantees message order only from one process to another. If process A sequentially sends message 1 and then message 2 to process B, then B will receive them in that order. But Erlang guarantees no specific ordering of messages arriving at B if multiple concurrent processes are sending them. In this example,
Parent
,Child1
, andChild2
all run concurrently and all send messages concurrently toServer
.The
Parent
process performs the following sequential steps:Server
process. This eventually sets the initial value in theServer
loop to0
.Child1
. This eventually writes the value2
toServer
, then reads fromServer
and prints the result.write/2
to send the value3
toServer
. Thewrite
case in theloop/1
function first replies to the caller and then installs the value3
for its next iteration.write2/2
to send5
toServer
. Thewrite2/2
function just sends a message toServer
and does not await a reply. Thewrite2
case in theloop/1
function just installs the value5
for its next iteration.Child2
, which eventually callswrite2/2
with the value1
, and then readsServer
and prints the result.Server
and prints the result.For
Parent
, step 3 sends the value3
toServer
, so as far asParent
is concerned,Server
now has the value3
. In step 4,Parent
callswrite2/2
to send5
to the server, and that message must arrive atServer
sometime after the message sent in step 3. In step 6,Parent
performs a read, but all we know is that this message has to arrive atServer
after the write message in step 4. This message ordering means the highest valueParent
can see is5
.The lowest value
Parent
can see is1
because ifChild2
gets its write message of1
toServer
after theParent
write message of5
but before the finalParent
read message, thenParent
will see the1
.For
Child1
, the highest value it can see is5
because it runs concurrently withParent
and the two messages sent byParent
could arrive atServer
before its write message of2
. The lowestChild1
can see is1
because theChild2
write message of1
can arrive before theChild1
read message.For
Child2
, the lowest value it can see is its own write of1
. The highest value it can see is2
from the write ofChild1
because theParent
writes of3
and5
occur beforeChild2
is spawned, thusChild1
is the only process writing concurrently and so only it has a chance of interleaving its write message between theChild2
write and read messages.