我目前正在阅读编程Erlang,在第13章的末尾,我们想要创建一个保持活力的过程,例如:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Info} ->
Fun(Info)
end
end).
keep_alive(Name, Fun) ->
register(Name, Pid = spawn(Fun)),
on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
但是当在register/2
和on_exit/2
之间时,进程可能会退出,所以监视器会失败,我把keep_alive/2
改成这样:
keep_alive(Name, Fun) ->
{Pid, Ref} = spawn_monitor(Fun),
register(Name, Pid),
receive
{'DOWN', Ref, process, Pid, _Info} ->
keep_alive(Name, Fun)
end.
还有一个错误,在spawn_monitor/2
和register/2
之间,进程可能会退出。这怎么会成功运行?谢谢
我不确定您是否有需要解决的问题。即使您的进程在注册/2之后退出,监视器/2也会成功。监视器/2将发送一条"向下"消息,其信息组件将为noproc。根据文件:
如果Item死亡,如果Item不存在,或者如果与Item所在节点的连接丢失,将向监控进程发送"DOWN"消息。(请参阅http://www.erlang.org/doc/man/erlang.html#monitor-2) 。
所以,在你的原始代码
- 注册关联方Pid的名称
- Pid死亡
- 调用on_exit并执行monitor/2
- 监视器立即发送一条"DOWN"消息,该消息由on_exit派生的函数接收
- 接收到的语句的Fun(Info)调用keep_alive/2执行
我觉得一切都很好。
为什么不想使用erlang主管行为?它为创建和重新启动保活进程提供了有用的功能。
请参见以下示例:http://www.erlang.org/doc/design_principles/sup_princ.html
在第二个示例中,如果进程在注册之前退出,register
将以badarg
失败。最简单的方法是用try ... catch
包围寄存器并处理catch中的错误。
您甚至可以将catch留空,因为即使注册失败,也会发送'DOWN'
消息。
另一方面,在生产系统中我不会这么做。如果你的工作人员失败得如此之快,很可能问题出在它的初始化代码中,我想知道,它未能注册并停止了系统。否则,它可能会失败,并在一个无休止的循环中重生。