views:

380

answers:

5

In Erlang is there any way that a message sender can wait on a response, so it only continues execution once the message has been processed?

And I mean something like this:

Actor ! DoSomething
Continue to this next line of code when DoSomething has been processed

I know a callback can be made by sending the Pid of the sender, but is there any other way to wait?

+1  A: 

You could use a receive block:

http://www.erlang.org/doc/reference_manual/expressions.html#id2270724

Reading from the doc:

receive never fails. Execution is suspended, possibly indefinitely, until a message arrives that does match one of the patterns and with a true guard sequence.

In other words, send a message and wait for a reply.

Roberto Aloi
hope there is a timeout somewhere ;-)
jldupont
isn't this a callback?
fortran
Yes, this is a callback :)
Zubair
A callback? Where?
Zed
Doesn't this send the Pid and waiting in a receive? And doesn't this make it a callback? I'm not sure myself, so can someone please help to explain it to me.
Zubair
@Zubair: If You say me "Hello!" and you will be wait for mine "Hello!" and I answer "Hello!". Is there any callback? It is how Erlang works. Just processes and messages. You are precess, I'm process. You send message, I send message. I receive, You receive. No callbacks here.
Hynek -Pichi- Vychodil
Ok, thanks @Hynek. I guess I misunderstood what a callback was.
Zubair
+2  A: 

If the receiving process is a gen_server, you can use gen_server:call. E.g.:

gen_server:call(Pid, Message),
% At this point, we know that the other process has answered.
legoscia
I am curious on how many real world applications are built with this technique.
jldupont
@jldupont. You ask a valid question, I'm not sure what the answer is. I will say this though : if you are building a non-trivial system on Erlang then you probably should be using OTP and hence gen_server:call(). If you don't use OTP then you'll end-up either re-inventing some of what OTP does for you, or code in a manner that doesn't play to Erlang's strengths... in which case you should probably be using a different language in the first place.
Tim
@Tim: to be more precise: I am curious of how popular `gen_server:call()` is compared to the asynchronous `gen_server:cast()` counterpart.
jldupont
`call` can be used for brokering any kind of resources, controlling the state of a server, requesting data from the server, server based load regulation, ...
Zed
the greatest thing that gen_server:call has is that you can block the caller by returning noreply immediately while preserving parallelism in your side by spawning a process to handle the call and return reply from there. Try to do this in java (easily). Sorry for the last comment but i wanted to take it out myself, and pay honor to this tiny golden pattern erlang(OTP to be fair) offers me for free...
Paralife
+12  A: 

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.

I GIVE TERRIBLE ADVICE
A: 

Just depends on the situations jldupont. If a web browser makes a request to webmachine for some long running erlang resource, there's no way to use a cast to fulfill that request.

blah
A: 

No, there is only asynchronous message passing.

If you want to be a little philosophical then it is very difficult to automatically define when a message has been processed. Is it when the message has arrived at the process, been received but not yet acted upon or at sometime when it has been acted upon by the receiving process. It is similar to getting automatic notification when someone has "read" my mail. Yes, they have seen it but they have really read it?

rvirding