First thing to understand is that Erlang was built to deal with asynchronous message passing. As such, the only way to have synchronous message passing is to implement something akin to an acknowledgement.
Imagine two processes, P1 and P2. P1 might run the following code:
%% process P1 takes the Pid of P2 as a parameter
%% and a Message to pass on to P2
p1(P2, Message) ->
P2 ! {self(), Message},
receive
{P2, ok}
after 5000 -> % this section is optional, times out after 5s
exit("P2 didn't process this!") % this kills P1
end.
P2, on its side might just run the following:
p2() ->
receive
{From, Message} ->
io:format("P2 received message ~p~n",[Message]),
%% processing is done!
From ! {self(), ok}
end.
So then you might spawn p2 as a new process. This one will sit waiting for any message. When you then call p1, it sends a message to P2, which then processes it (io:format/2
) and replies to P1. Because P1 was waiting for a reply, no additional code was run inside that process.
That's the basic and only way to implement blocking calls. The suggestions to use gen_server:call
roughly implement what I've just shown. It's hidden from the programmer, though.