一个进程可以有两个接收块

时间:2012-12-01 15:59:45

标签: process erlang

我的工作环境是Erlang。 具有2个不同功能的进程是否可以在不同的功能中具有两个接收块。

receive
....
end.

request()
PID!(message)
%% Can i get the reply back here instead of the receive block above?

2 个答案:

答案 0 :(得分:11)

是的,你可以有很多receive个表达式。当评估一个时,它将从消息队列/邮箱中取出第一个匹配的消息(选择你的名字),剩下的就留给下一个receive。使用Pid ! Message语法(唯一的方法)发送消息是完全异步的,只是将消息添加到接收进程消息队列的末尾。 receive接收消息的唯一方法,即将它们从消息队列中取出。你永远不能把它们放回去。

在Erlang中没有内置的同步消息传递,它通过发送两条消息来传递:

  • “请求”流程向接收流程发送消息,然后进入receive等待回复。

  • “接收”流程本身会在receive中收到邮件,对其进行处理,将回复邮件发送回“请求”流程,然后进入receive进行访问并等待下一条消息。

请记住,进程之间没有固有的连接,并且所有通信都是使用异步消息发送和receive完成的。

因此,在回答您的第二个问题时:您可以receive表达式中获得回复。这是唯一的方法!

很抱歉有点迂腐,但Erlang没有块或语句。它是一种函数式语言,只有表达式,即使有时会忽略返回值,它总是返回一个值。

答案 1 :(得分:2)

当然,你可以。

  

使用send运算符(!)接收发送到进程的消息。该   模式模式与第一条消息顺序匹配   邮箱中的时间顺序,然后是第二个,依此类推。如果匹配   成功并且可选的保护序列GuardSeq是真的,   对应的Body进行评估。消耗匹配的消息,   从邮箱中删除,而在邮箱中删除任何其他邮件   邮箱保持不变。

以下代码来自supervisor2.erl项目的rabbitmq。它甚至使用嵌套的receive语句。我在下面标记了嵌套receive

terminate_simple_children(Child, Dynamics, SupName) ->
    Pids = dict:fold(fun (Pid, _Args, Pids) ->
                         erlang:monitor(process, Pid),
                         unlink(Pid),
                         exit(Pid, child_exit_reason(Child)),
                         [Pid | Pids]
                     end, [], Dynamics),
    TimeoutMsg = {timeout, make_ref()},
    TRef = timeout_start(Child, TimeoutMsg),
    {Replies, Timedout} =
        lists:foldl(
          fun (_Pid, {Replies, Timedout}) ->
                  {Reply, Timedout1} =
                      receive %% attention here 
                          TimeoutMsg ->
                              Remaining = Pids -- [P || {P, _} <- Replies],
                              [exit(P, kill) || P <- Remaining],
                              receive {'DOWN', _MRef, process, Pid, Reason} -> %%attention here
                                      {{error, Reason}, true}
                              end;
                          {'DOWN', _MRef, process, Pid, Reason} ->
                              {child_res(Child, Reason, Timedout), Timedout};
                          {'EXIT', Pid, Reason} -> 
                              receive {'DOWN', _MRef, process, Pid, _} ->
                                      {{error, Reason}, Timedout}
                              end
                      end,
                  {[{Pid, Reply} | Replies], Timedout1}
          end, {[], false}, Pids),
    timeout_stop(Child, TRef, TimeoutMsg, Timedout),
    ReportError = shutdown_error_reporter(SupName),
    [case Reply of
         {_Pid, ok}         -> ok;
         {Pid,  {error, R}} -> ReportError(R, Child#child{pid = Pid})
     end || Reply <- Replies],
    ok.