[英]Erlang: spawning process with monitor
I'm working through Joe Armstrong's Programming Erlang 2nd E .我正在研究 Joe Armstrong 的Programming Erlang 2nd E 。 The book has exercises at the end of each chapter.本书每章末尾附有习题。 Chapter 13, exercise 1 says:第 13 章,练习 1 说:
Write a function
my_spawn(Mod, Func, Args)
that behaves likespawn(Mod, Func, Args)
but with one difference.编写一个函数my_spawn(Mod, Func, Args)
,它的行为类似于spawn(Mod, Func, Args)
但有一个区别。 If the spawned process dies, a message should be printed saying why the process died and how long the process lived for before it died.如果生成的进程死了,应该打印一条消息,说明该进程死的原因以及该进程在死之前存活了多长时间。
Here's a solution that has a race condition:这是一个具有竞争条件的解决方案:
my_spawn(Mod, Func, Args) ->
Pid = spawn(Mod, Func, Args),
spawn(fun() ->
Ref = monitor(process, Pid),
T1 = erlang:monotonic_time(millisecond),
receive
{'DOWN', Ref, process, Pid, Why} ->
io:format("~p died because of ~p~n", [Pid, Why]),
io:format("~p lived for ~p ms~n", [Pid, erlang:monotonic_time(millisecond) - T1])
end
end),
Pid.
Spawning the process and creating the monitor is not an atomic step, so if the process dies after spawning but before the monitor is created, we won't get the error message.生成进程并创建监视器不是原子步骤,因此如果进程在生成后但在创建监视器之前终止,我们将不会收到错误消息。
Here's an attempt without the race condition:这是没有竞争条件的尝试:
my_spawn_atomic(Mod, Func, Args) ->
spawn(fun() ->
{Pid, Ref} = spawn_monitor(Mod, Func, Args),
T1 = erlang:monotonic_time(millisecond),
receive {'DOWN', Ref, process, Pid, Why} ->
io:format("~p died because of ~p~n", [Pid, Why]),
io:format("~p lived for ~p ms~n", [Pid, erlang:monotonic_time(millisecond) - T1])
end
end).
But the PID this returns is that of the monitoring process, not the Func
process.但是这个返回的PID是监控进程的PID,而不是Func
进程的PID。 And given that spawn
always returns the PID of the process it creates, there doesn't seem to be a way to return Pid
without resorting to a side effect.鉴于spawn
总是返回它创建的进程的 PID,似乎没有办法在不诉诸副作用的情况下返回Pid
。
What's the idiomatic way to do implement the atomic spawning?实现原子生成的惯用方法是什么?
You can send Pid from monitoring process as a message:您可以从监控进程发送 Pid 作为消息:
my_spawn_atomic(Mod, Func, Args) ->
Parent = self(),
MPid = spawn(fun() ->
{Pid, Ref} = spawn_monitor(Mod, Func, Args),
Parent ! {spawned, self(), Pid},
T1 = erlang:monotonic_time(millisecond),
receive {'DOWN', Ref, process, Pid, Why} ->
io:format("~p died because of ~p~n", [Pid, Why]),
io:format("~p lived for ~p ms~n", [Pid, erlang:monotonic_time(millisecond) - T1])
end
end),
receive
{spawned, MPid, Pid} -> Pid
after 1000 -> error % 1s should be way enough for spawning monitoring process
end.
Another option is to wrap the function in a fun with an init phase :另一种选择是将函数包装在一个有趣的 init 阶段:
my_spawn(Mod, Func, Args) ->
Pid = spawn(fun() ->
receive run -> apply(Mod, Func, Args)
after 1000 -> exit(init_timeout)
end
end),
spawn(fun() ->
Ref = monitor(process, Pid),
T1 = erlang:monotonic_time(millisecond),
Pid ! run,
receive
{'DOWN', Ref, process, Pid, Why} ->
io:format("~p died because of ~p~n", [Pid, Why]),
io:format("~p lived for ~p ms~n", [Pid, erlang:monotonic_time(millisecond) - T1])
end
end),
Pid.
http://marcelog.github.io/articles/erlang_link_vs_monitor_difference.html http://marcelog.github.io/articles/erlang_link_vs_monitor_difference.html
The difference between spawn_link and spaw_monitor is well explained here. spawn_link 和 spaw_monitor 之间的区别在这里有很好的解释。
-module(mon_test).
-export([my_spawn/3, die_in/1]).
my_spawn(Mod, Func, Args) ->
spawn(my_spawn(mon_test, my_spawn, [self(), Mod, Func, Args]),
receive
Pid -> Pid
after 1000 -> timeout
end.
my_spawn(Parent, Mod, Func, Args) ->
{Pid, Ref} = spawn_monitor(Mod, Func, Args),
T1 = erlang:system_time(),
Parent ! Pid,
receive
{'DOWN', Ref, _Any, Pid, Why} ->
io:format("~p died because of ~p, lived for ~p milliseconds~n", [Pid, Why, (erlang:system_time()-T1)/1000/1000])
end.
die_in(Secs) ->
receive
Reason -> exit(Reason)
after Secs*1000 -> exit(timeout_reason)
end.
> mon_test:my_spawn(mon_test, die_in, [5]).
<0.155.0>
<0.155.0> died because of timeout_reason, lived for 5001.152 milliseconds
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.