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