产卵和接收的二郎种族条件

时间:2015-02-18 09:09:52

标签: erlang

我正在用书学习erlang,在第13章中,第一个练习是编写一个函数my_spawn,它在生成的消息崩溃/退出时捕获退出消息。

-module(my_spawn1).
-compile(export_all).

my_spawn(Mod,Func,Args) ->
    {M1, S1, Mi1} = os:timestamp(),
    Pid = spawn(Mod,Func,Args),
    lib_misc:on_exit(Pid, fun(Why) ->
                  {M2,S2,Mi2} = os:timestamp(),
                  ElapsedTime = (M2 - M1) * 1000000 + (S2 - S1) * 1000 + (Mi2-Mi1),
                  io:format("~p died with:~p~n consume time:~p(ms)", [Pid,Why,ElapsedTime]),
              end),
    Pid.

我的困惑是,如果在spawn_monitor之后,Mod:Func(Args)已完成,但lib_misc:on_exit(...)尚未设置,那么退出消息将会丢失,真的吗?

如果这是正确的,那么如何抓住这种情况呢?

[由Pascal编辑]

我添加了lib_misc的代码:on_exit / 2

on_exit(Pid, Fun) ->
    spawn(fun() -> 
          process_flag(trap_exit, true), %% <label id="code.onexit1"/>
          link(Pid),                     %% <label id="code.onexit2"/>
          receive
              {'EXIT', Pid, Why} ->      %% <label id="code.onexit3"/>
              Fun(Why)   %% <label id="code.onexit4"/>
          end
      end).

2 个答案:

答案 0 :(得分:1)

不,消息(与所有消息一样)将排队。但是,如果接收消息的进程消失,则其邮箱将丢失。

如果A使spawn_monitor产生B,并且B立即死亡,则A保证接收DOWN消息。但是,如果A也死了,那么A的消息队列中的所有内容都将丢失。

答案 1 :(得分:1)

on_exit函数的第一件事就是生成一个将process_flag trap_exit设置为true的进程,因此它可以“防止”崩溃,并将接收类型为{'EXIT', Pid, Why}的消息。

在下一行,它尝试将自己链接到Pid;有两种情况可能:

  • Pid不存在(错误的值,已经死了......)然后on_exit进程将收到消息{'EXIT', Pid, noproc}并将调用F(noproc)。
  • Pid存在,然后on_exit进程将等待接收,直到进程Pid因某些原因而死亡。 on_exit将收到{'EXIT', Pid, Reason}并致电F(原因)。

我不明白你为什么谈论spawn_monitor,它不会在你的情况下使用。无论如何,如果你在on_exit函数中用监视器(进程,Pid)替换链接(Pid),你甚至不需要使用trap_exit,因为如果Pid死了,监视器功能不会崩溃。在所有情况下,它都会返回消息{'DOWN',MonitorReference,process,Pid,Reason}。 on_exit可以像这样修改:

on_exit(Pid, Fun) ->
    spawn(fun() -> 
          MonitorReference = monitor(process,Pid),
          receive
              {'DOWN',MonitorReference,process,Pid,Why} -> Fun(Why)
          end
      end).