Why second call to receive doesn't retrieve a message in Erlang shell?

Viewed 798

I'm playing with processes in Erlang and trying to create a simple counter process. It receives a PID of a sender, increments inner counter and sends new counter value to the sender. I'm launching my code from erl shell (Erlang/OTP 20, Eshell V9.2). And I'm able to successfully receive first reply from the counter process, but not the second.

%% Process function that serves as a counter
CounterFun = fun() ->
  (fun Receiver(Current) ->
    io:format("  -- Entering receiver, current ~p~n", [Current]),
    receive
      Sender ->
        New = Current + 1,
        io:format("  -- Sending ~p to ~p~n", [New, Sender]),
        Sender ! New,
        Receiver(New)
    end
  end)(0)
end.

CounterPid = spawn(CounterFun).

CounterPid ! self().
receive V -> V after 3000 -> timeout end. % Will provide 1

CounterPid ! self().
receive V -> V after 3000 -> timeout end. % Will result in timeout

Here how it looks like in my console. enter image description here

1 Answers

The first receive binds the variable V to 1, so the second receive becomes:

receive 
    1 -> ...

end

And, because the message 1 never arrives, the second receive times out. After the timeout, you can call flush() in the shell, and you will see that there was a message 2 in the mailbox. You can also call b() at any time to display the current variables and their values (which are known as bindings)--try that after executing the first receive.

In your function, you are also doing a recursive receive within a receive within a receive such that the first receive never ends. To prove that, you can put a print statement after:

Receiver(New)

like:

io:format("receive ending with Current= ~w~n", [Current])

and you will never see any output. You should change your receive to something like this:

New = Currrent + 1
receive
  Sender ->
    io:format("  -- Sending ~p to ~p~n", [New, Sender]),
    Sender ! New,
    io:format("receive ending with Current= ~w~n", [Current])
end,
counter(New).
Related