[英]erlang race condition of spawn and receive
我正在用書學習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).
不,該消息(如所有消息)將排隊。 但是,如果接收該消息的進程死亡,則其郵箱將丟失。
如果A確實執行spawn_monitor
來生成B,並且B立即死亡,則保證A收到DOWN消息。 但是,如果A也死了,那么A的消息隊列中的所有內容都會丟失。
函數on_exit要做的第一件事是生成一個將process_flag trap_exit設置為true的進程,因此該進程被“保護”免於崩潰,並且將接收類型為{'EXIT', Pid, Why}
。
在下一行中,它嘗試將自身鏈接到Pid; 可能有2種情況:
{'EXIT', Pid, noproc}
,並調用F(noproc)。 {'EXIT', Pid, Reason}
並致電F(原因)。 我不明白您為什么談論spawn_monitor,在您的情況下沒有使用它。 無論如何,如果在on_exit函數中用monitor(process,Pid)替換link(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).
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.