如何在列表中重新启动erlang进程?

时间:2014-03-14 11:00:11

标签: list erlang

我有一个像这样的列表结构:

[{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List]

所以我有一个包含值的列表,每个值都在上面的行中传递给它自己的进程。如果一个工人死了,我想重新启动它(具有相同的值)。我已将Value保存在与上述新流程相同的tupel中。我可以做一些列表理解来确定过程是否已经死亡,在这种情况下,开始一个新的吗?

3 个答案:

答案 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重启策略。