Erlang:带监视器的生成过程
我在乔·阿姆斯特朗家工作。这本书每章末尾都有练习。第13章练习1说: 编写一个函数Erlang:带监视器的生成过程,erlang,monitoring,spawn,Erlang,Monitoring,Spawn,我在乔·阿姆斯特朗家工作。这本书每章末尾都有练习。第13章练习1说: 编写一个函数my_spawn(Mod,Func,Args),其行为类似于spawn(Mod,Func,Args),但有一个区别。如果生成的进程死亡,则应打印一条消息,说明该进程死亡的原因以及该进程在死亡前的生存时间 以下是一个具有竞争条件的解决方案: my_spawn(Mod、Func、Args)-> Pid=spawn(Mod、Func、Args), 繁殖(乐趣()-> Ref=监视器(过程,Pid), T1=erlang:
my_spawn(Mod,Func,Args)
,其行为类似于spawn(Mod,Func,Args)
,但有一个区别。如果生成的进程死亡,则应打印一条消息,说明该进程死亡的原因以及该进程在死亡前的生存时间
以下是一个具有竞争条件的解决方案:
my_spawn(Mod、Func、Args)->
Pid=spawn(Mod、Func、Args),
繁殖(乐趣()->
Ref=监视器(过程,Pid),
T1=erlang:单调时间(毫秒),
接收
{'DOWN',Ref,process,Pid,Why}->
io:format(~p因为~p~n而死亡,[Pid,为什么]),
io:format(“~p为~p ms~n生存,[Pid,erlang:monotonic_time(毫秒)-T1])
结束
(完),,
Pid。
生成进程并创建监视器不是一个原子步骤,因此如果进程在生成后但在创建监视器之前死亡,我们将不会收到错误消息
下面是一个没有比赛条件的尝试:
my_spawn_atomic(Mod、Func、Args)->
繁殖(乐趣()->
{Pid,Ref}=spawn_监视器(Mod,Func,Args),
T1=erlang:单调时间(毫秒),
接收{'DOWN',Ref,process,Pid,Why}->
io:format(~p因为~p~n而死亡,[Pid,为什么]),
io:format(“~p为~p ms~n生存,[Pid,erlang:monotonic_time(毫秒)-T1])
结束
(完)。
但是它返回的PID是监视进程的PID,而不是Func
进程的PID。考虑到spawn
总是返回它创建的进程的PID,似乎没有一种方法可以返回PID
,而不会产生副作用
实现原子繁殖的惯用方法是什么?
这里很好地解释了spaw_链接和spaw_监视器之间的区别
-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
-模块(mon\u测试)。
-导出([my_spawn/3,die_in/1])。
我的产卵(Mod、Func、Args)->
繁殖(my_繁殖(mon_测试,my_繁殖,[self(),Mod,Func,Args]),
接收
Pid->Pid
1000后->超时
结束。
my_spawn(父、模、函数、参数)->
{Pid,Ref}=spawn_监视器(Mod,Func,Args),
T1=erlang:system\u time(),
家长!Pid,
接收
{'DOWN',Ref,_Any,Pid,Why}->
io:format(“~p因为~p而死亡,生存了~p毫秒~n”,[Pid,为什么,(erlang:system_time()-T1)/1000/1000])
结束。
死亡时间(秒)->
接收
原因->退出(原因)
秒后*1000->退出(超时原因)
结束。
>mon_测试:我的产卵(mon_测试,死亡[5])。
因超时原因死亡,存活5001.152毫秒
您可以通过消息的形式从监控流程发送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.
另一个选项是通过初始化阶段将函数包装成一个有趣的形式:
你应该看一看。另请看。如何使用
spawn\u link
帮助?我已经在使用spawn\u monitor
。正如前面提到的,原子繁殖已经实现为。顺便说一句,也许你还发现了LYSE中有趣的一章。为什么你要将所有内容都包装在spawn中?只要去掉spawn,它就会工作得很好。嗯……这个似乎是一种足够常见的模式,我认为有一种更简单的方法可以做到这一点,但你的两种解决方案都是有效的。也许这些模式是作为某些内置行为的一部分被捕获的…@田祥雄:不,不是。在这种分离的监视器中几乎没有什么用处。有一种常见的模式你希望你的进程与su一起消亡b进程,反之亦然,在这里您可以使用spawn_link
,并且有一个您想要监视其他进程的通用模式,并且没有分离的派生监视器,因此您可以使用spawn_monitor
,并且有一个带有工作人员和主管树的OTP。除了教育模式之外,您的模式几乎没有实际用途。
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.