Erlang:带监视器的生成过程

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:

我在乔·阿姆斯特朗家工作。这本书每章末尾都有练习。第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:单调时间(毫秒),
接收
{'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.