我有一个像这样的列表结构:
[{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List]
所以我有一个包含值的列表,每个值都在上面的行中传递给它自己的进程。如果一个工人死了,我想重新启动它(具有相同的值)。我已将Value保存在与上述新流程相同的tupel中。我可以做一些列表理解来确定过程是否已经死亡,在这种情况下,开始一个新的吗?
答案 0 :(得分:1)
使用erlang:monitor / 2来监视您的进程:
List1 = [{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List],
List2 = [{Value, Pid, monitor(process, Pid)} || {Value, Pid} <- List1]
然后等待监视器的消息,在需要时重新启动进程并使用新的pid和监视器更新List2。
要获取有关erlang的更多信息:monitor / 2阅读相应的手册页。
答案 1 :(得分:1)
首先,创建一个函数,创建一个监视Pid
的进程,并在它死亡时执行Fun
,如下所示:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
Fun(Why)
end
end).
现在,您可以使用on_exit
函数创建一个函数来创建在进程终止时自动重新启动的进程:
keep_alive(Fun) ->
process_flag(trap_exit, true),
Pid = spawn_link(Fun),
on_exit(Pid, fun(Why) ->
io:format("Process died: ~p, restarting it~n", [Why]),
keep_alive(Fun) end),
Pid.
使用这两个小功能,您创建将自动重启的流程的工作减少到只需在列表理解中调用keep_alive
:
[{Value, keep_alive(fun() -> worker(Value, self()) end)} || Value <- List].
PS:这两个小函数在本书Programming Erlang 2nd Edition的第13章中几乎完全相同,我只做了一些小改动,以更好地适应你的情况。
答案 2 :(得分:1)
在你自制的主管中,不要忘记设置process_flag(trap_exit, true)
否则它会在一个孩子死亡的同时死亡,然后是所有其他孩子:
1> F = fun() -> timer:sleep(2000) end.
#Fun<erl_eval.20.80484245>
2> F1 = fun() -> timer:sleep(2000), 1/0 end.
#Fun<erl_eval.20.80484245>
3> S = fun() -> spawn_link(F), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
4> S1 = fun() -> spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
5> S1b = fun() -> process_flag(trap_exit, true), spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
6> self().
<0.40.0>
7> S().
no_message
8> self().
<0.40.0>
9> S1().
=ERROR REPORT==== 15-Mar-2014::06:46:27 ===
Error in process <0.49.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
** exception exit: badarith
in operator '/'/2
called as 1 / 0
10> self().
<0.50.0>
11> S1b().
=ERROR REPORT==== 15-Mar-2014::06:46:39 ===
Error in process <0.53.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
{'EXIT',<0.53.0>,{badarith,[{erlang,'/',[1,0],[]}]}}
12> self().
<0.50.0>
13>
除非您出于教育目的而这样做,否则我建议您使用erlang otp主管,并使用one_for_one重启策略。