Erlang主进程终止从进程

clj7thdc  于 2024-01-04  发布在  Erlang
关注(0)|答案(2)|浏览(290)

我正在学习Erlang,对下面的代码感到困惑:

  1. -module(killing_master).
  2. -export([start/1, loop/1]).
  3. start(SlavesNum) ->
  4. process_flag(trap_exit, true),
  5. [spawn_link(fun() ->
  6. io:format("slave ~p~n", [N]),
  7. loop(N)
  8. end) || N <- lists:seq(1, SlavesNum)],
  9. spawn_link(fun() -> process_flag(trap_exit, true), init() end),
  10. exit(normal).
  11. init() ->
  12. receive
  13. {'EXIT', From, Why} -> io:format("start: (~p) exited ~p ~p~n", [self(), From, Why]);
  14. Catch -> io:format("~p~n", [Catch])
  15. end.
  16. loop(SlaveNum) ->
  17. receive
  18. Msg -> io:format("slave #~p received ~p~n", [SlaveNum, Msg])
  19. end.

字符串
我所期望的行为是,在主服务器退出之后,所有的从服务器也应该退出(因为spawn_link),在这样做之前打印一条消息;而我得到的是:

  1. 1> killing_master:start(10).
  2. slave 1
  3. slave 2
  4. slave 3
  5. slave 4
  6. slave 5
  7. slave 6
  8. slave 7
  9. slave 8
  10. slave 9
  11. slave 10
  12. ** exception exit: normal

webghufk

webghufk1#

原因可能是主进程甚至在从进程生成之前就已经死亡,因此从进程不能监视已经退出的进程。
你可以稍微修改代码,引入一个睡眠延迟来保持主进程一段时间的活动:

  1. start(SlavesNum) ->
  2. process_flag(trap_exit, true),
  3. [spawn_link(fun() ->
  4. io:format("slave ~p~n", [N]),
  5. loop(N)
  6. end) || N <- lists:seq(1, SlavesNum)],
  7. spawn_link(fun() -> process_flag(trap_exit, true), init() end),
  8. timer:sleep(100), %%% <---- add sleep here
  9. exit(normal).

字符串
然后,您应该能够看到这样的消息:

  1. 41> killing_master:start(10).
  2. slave 1
  3. slave 2
  4. slave 3
  5. slave 4
  6. slave 5
  7. slave 6
  8. slave 7
  9. slave 8
  10. slave 9
  11. slave 10
  12. start: (<0.414.0>) exited <0.397.0> normal
  13. ** exception exit: normal

展开查看全部
3yhwsihp

3yhwsihp2#

我所期望的行为是,在master退出之后,所有slave也应该退出(因为spawn_link),在这样做之前打印一条消息
另外,没有一个从进程捕获退出,所以当它们收到退出信号时不会打印消息。

  1. [spawn_link(fun() ->
  2. io:format("slave ~p~n", [N]),
  3. loop(N)
  4. end)
  5. || N <- lists:seq(1, SlavesNum)],

字符串
并且,每个从属进程运行以下函数:

  1. fun() ->
  2. io:format("slave ~p~n", [N]),
  3. loop(N)
  4. end


loop/1函数也不会捕获exit。
下面是一些简单的代码,您可以尝试:

  1. -module(a).
  2. -compile(export_all).
  3. master() ->
  4. process_flag(trap_exit, true),
  5. io:format("master pid: ~w~n", [self()]),
  6. spawn_link(fun slave/0),
  7. receive
  8. {'EXIT', From, Why} ->
  9. io:format("master(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
  10. [self(), From, Why]);
  11. Any ->
  12. io:format("master(): non-exit message... ~w~n", [Any])
  13. end.
  14. slave() ->
  15. process_flag(trap_exit, true),
  16. io:format("slave 1~n"),
  17. receive
  18. {'EXIT', From, Why} ->
  19. io:format("slave(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
  20. [self(), From, Why]);
  21. Any ->
  22. io:format("slave(): non-exit message... ~w~n", [Any])
  23. end.


在shell中:

  1. ~/erlang_programs% erl
  2. Erlang/OTP 24 [erts-12.3.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]
  3. Eshell V12.3.2 (abort with ^G)
  4. 1> c(a).
  5. a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
  6. % 2| -compile(export_all).
  7. % | ^
  8. {ok,a}
  9. 2> Master = spawn(a, master, []).
  10. master pid: <0.90.0>
  11. <0.90.0>
  12. slave 1
  13. 3> exit(Master, normal).
  14. master(): Process (<0.90.0>) exited
  15. Exit signal from: <0.83.0>
  16. Reason: normal
  17. true
  18. slave(): Process (<0.91.0>) exited
  19. Exit signal from: <0.90.0>
  20. Reason: normal
  21. 4> self().
  22. <0.83.0>


原因可能是主人甚至在奴隶孩子出生之前就死了。
在这种情况下,我会认为spawn_link会返回类似{nolink, new_pid}的内容。奇怪的是,没有办法知道链接是否成功。您可以使用以下代码确认主进程实际上已经退出:

  1. -module(a).
  2. -compile(export_all).
  3. master() ->
  4. io:format("master pid: ~w~n", [self()]),
  5. spawn_link(fun slave/0).
  6. slave() ->
  7. process_flag(trap_exit, true),
  8. io:format("slave 1~n"),
  9. receive
  10. {'EXIT', From, Why} ->
  11. io:format("slave(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
  12. [self(), From, Why]);
  13. Any ->
  14. io:format("slave(): non-exit message... ~w~n", [Any])
  15. end.


在shell中:

  1. > c(a).
  2. a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
  3. % 2| -compile(export_all).
  4. % | ^
  5. {ok,a}
  6. 2> Master = spawn(a, master, []).
  7. master pid: <0.90.0>
  8. <0.90.0>
  9. slave 1
  10. 3> i().
  11. ...
  12. ...
  13. disk_log_server gen_server:loop/7 12
  14. <0.80.0> disk_log:init/2 4185 12507 0
  15. disk_log:loop/1 7
  16. <0.82.0> erlang:apply/2 28690 19928 0
  17. shell:shell_rep/4 18
  18. <0.83.0> erlang:apply/2 121536 46746 0
  19. c:pinfo/1 49
  20. <0.91.0> erlang:apply/2 233 33 0
  21. a:slave/0 2
  22. Total 213936 561931 0


master()进程的pid是<0.90.0>,但没有列出,您可以看到slave()正在<0.91.0>进程中运行。或者,您可以调用:

  1. 4> is_process_alive(Master).
  2. false


然而,slave()没有输出任何退出消息。结论是,主进程在从进程链接到它之前就退出了。
因此,您的程式码会有两个问题:
1.主进程永远不会链接到从属进程。
1.即使主进程链接到从属进程,从属进程也不会捕获退出,因此它们不会打印出退出消息。

展开查看全部

相关问题