问题
I am learning erlang with book , In chapter 13, the first exercise is writing a function my_spawn, which catch exit message when spawned message crash/exited.
-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.
my confuse was, if after spawn_monitor, the Mod:Func(Args) was finished, but the lib_misc:on_exit(...) haven't setup, so the exit message will be lost, really ?
If that's correct, so how to catch this situation ?
[edit by Pascal]
I add the code for 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).
回答1:
The first thing the function on_exit does is to spawn a process that set the process_flag trap_exit to true, thus it is "protected" from crashes, and will receive instead messages of the type: {'EXIT', Pid, Why}.
On the next line it tries to link itself to Pid; 2 cases are possible:
- the Pid does not exists (wrong value, already dead...) then the on_exit process will receive the message
{'EXIT', Pid, noproc}and will call F(noproc). - the Pid exists, then the on_exit process will wait on receive until the process Pid dies for some Reason. on_exit will receive
{'EXIT', Pid, Reason}and call F(Reason).
I don't understand why you speak about spawn_monitor, it is not used in your case. Anyway, if you replace link(Pid) by monitor(process,Pid) in the on_exit function, you even don't need to use trap_exit since the monitor function don't crash if the Pid is dead. In all cases it returns the message {'DOWN',MonitorReference,process,Pid,Reason}. on_exit could be modified like this:
on_exit(Pid, Fun) ->
spawn(fun() ->
MonitorReference = monitor(process,Pid),
receive
{'DOWN',MonitorReference,process,Pid,Why} -> Fun(Why)
end
end).
回答2:
No, the message (like all messages) will be queued. If the process receiving the message dies, though, its mailbox is lost.
If A does spawn_monitor to spawn B, and B dies instantly, A is guaranteed to receive the DOWN message. If, however, A also dies, then everything in A's message queue is lost.
来源:https://stackoverflow.com/questions/28579698/erlang-race-condition-of-spawn-and-receive