【问题标题】:erlang race condition of spawn and receive生成和接收的erlang竞争条件
【发布时间】:2015-02-18 19:48:16
【问题描述】:

我正在用书学习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(...) 尚未设置,那么退出消息将丢失,真的吗?

如果是正确的,那么如何捕捉这种情况?

[帕斯卡编辑]

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

【问题讨论】:

    标签: erlang


    【解决方案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(Reason)。

    我不明白你为什么说 spawn_monitor,它没有在你的情况下使用。无论如何,如果你在 on_exit 函数中用 monitor(process,Pid) 替换 link(Pid),你甚至不需要使用 trap_exit,因为如果 Pid 死了,monitor 函数不会崩溃。在所有情况下,它都会返回消息{'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).
    

    【讨论】:

    • 好的,如果监听进程在receive之前退出但是在create monitor之后,会发生什么?
    • 我使用的是监视器,而不是系统进程,它将 trap_exit 的 process_flag 设置为真/
    • 你是对的,noproc 或 noconnection 将是原因
    • 这是否意味着在创建进程时创建了邮箱,即使您不对其调用接收命令?
    • 是的,邮箱是用进程创建的,它可以在到达任何receive语句之前存储传入的消息。
    【解决方案2】:

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

    如果 A 使用spawn_monitor 生成 B,而 B 立即死亡,则 A 肯定会收到 DOWN 消息。但是,如果 A 也死了,那么 A 的消息队列中的所有内容都会丢失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-31
      • 2020-07-12
      • 1970-01-01
      相关资源
      最近更新 更多