Erlang主进程终止从进程

clj7thdc  于 11个月前  发布在  Erlang
关注(0)|答案(2)|浏览(201)

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

-module(killing_master).
-export([start/1, loop/1]).

start(SlavesNum) ->
    process_flag(trap_exit, true),
    [spawn_link(fun() ->
                        io:format("slave ~p~n", [N]),
                        loop(N)
                end) || N <- lists:seq(1, SlavesNum)],
    spawn_link(fun() -> process_flag(trap_exit, true), init() end),
    exit(normal).

init() ->
    receive
        {'EXIT', From, Why} -> io:format("start: (~p) exited ~p ~p~n", [self(), From, Why]);
        Catch -> io:format("~p~n", [Catch])
    end.

loop(SlaveNum) ->
    receive
        Msg -> io:format("slave #~p received ~p~n", [SlaveNum, Msg])
    end.

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

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

webghufk

webghufk1#

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

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

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

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

3yhwsihp

3yhwsihp2#

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

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

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

fun() ->
    io:format("slave ~p~n", [N]),
    loop(N)                 
end


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

-module(a).
-compile(export_all).

master() ->
    process_flag(trap_exit, true),

    io:format("master pid: ~w~n", [self()]),
    spawn_link(fun slave/0),

    receive
        {'EXIT', From, Why} ->
            io:format("master(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
                      [self(), From, Why]);
        Any ->
            io:format("master(): non-exit message... ~w~n", [Any])
    end.

slave() -> 
    process_flag(trap_exit, true),

    io:format("slave 1~n"),

    receive
        {'EXIT', From, Why} ->
            io:format("slave(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
                      [self(), From, Why]);
        Any ->
            io:format("slave(): non-exit message... ~w~n", [Any])
    end.


在shell中:

~/erlang_programs% erl
Erlang/OTP 24 [erts-12.3.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]
Eshell V12.3.2  (abort with ^G)

1> c(a).                         
a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
%    2| -compile(export_all).
%     |  ^

{ok,a}

2> Master = spawn(a, master, []).
master pid: <0.90.0>
<0.90.0>
slave 1

3> exit(Master, normal).         
master(): Process (<0.90.0>) exited
Exit signal from: <0.83.0>
Reason: normal
true
slave(): Process (<0.91.0>) exited
Exit signal from: <0.90.0>
Reason: normal

4> self().
<0.83.0>


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

-module(a).
-compile(export_all).

master() ->
    io:format("master pid: ~w~n", [self()]),
    spawn_link(fun slave/0).

slave() -> 
    process_flag(trap_exit, true),
    io:format("slave 1~n"),

    receive
        {'EXIT', From, Why} ->
            io:format("slave(): Process (~w) exited~nExit signal from: ~w~nReason: ~w~n",
                      [self(), From, Why]);
        Any ->
            io:format("slave(): non-exit message... ~w~n", [Any])
    end.


在shell中:

> c(a).                         
a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
%    2| -compile(export_all).
%     |  ^

{ok,a}

2> Master = spawn(a, master, []).
master pid: <0.90.0>
<0.90.0>
slave 1

3> i().
...
...
disk_log_server       gen_server:loop/7                       12              
<0.80.0>              disk_log:init/2                       4185    12507    0
                      disk_log:loop/1                          7              
<0.82.0>              erlang:apply/2                       28690    19928    0
                      shell:shell_rep/4                       18              
<0.83.0>              erlang:apply/2                      121536    46746    0
                      c:pinfo/1                               49              
<0.91.0>              erlang:apply/2                         233       33    0
                      a:slave/0                                2              
Total                                                     213936   561931    0


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

4> is_process_alive(Master).
false


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

相关问题