1

伙计们,
我有一个关于 Erlang gen_server 的问题。
代码片段在这里:
文件:akita_cluster_info.erl

start_link() ->
    gen_server:start_link({global, ?MODULE}, ?MODULE, [], []).

init([]) ->
    c:nl(akita_collector_local),
    rpc:multicall(akita_collector_local, start, []),
    {ok, #state{}}.  

文件:akita_collector_local.erl

start() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 

init([]) ->
    %%process_flag(trap_exit, true),
    init_dets_file(),
    io:format("dic: ~w~n", [get()]),
    {ok, #state{}}.  

shell 的输出是这样的:
不要陷阱退出:

Eshell V5.9.1(使用 ^G 中止)
(akita@hao)1> akita_cluster_info:start_link()。
dic: [{'$ancestors',[<0.50.0>]},{'$initial_call',{akita_collector_local,init,1}}]
接收信息:{init_dets,{akita@hao,ok}}
{ok, <0.48.0>}
(秋田@hao)2>

陷阱出口:

Eshell V5.9.1(使用 ^G 中止)
(akita@hao)1> akita_cluster_info:start_link()。
dic: [{'$ancestors',[<0.50.0>]},{'$initial_call',{akita_collector_local,init,1}}] 终止原因:正常
接收信息:{init_dets,{akita@hao,ok }}
接收信息:{collector_close,{akita@hao,normal}}
{ok,<0.48.0>}
(akita@hao)2>

如果process_flag(trap_exit, true)没有注释,则akita_collector_local gen_server 进程将立即退出,因为它的父进程(在 rpc:multicall 中生成)死亡。我知道这很正常。
奇怪的是,没有process_flag(trap_exit, true)的时候,akita_collector_local gen_server 进程还能存活!!既然不能trap exit,它应该马上就退出了。(这个理论是正确的,我在 Erlang shell 中测试过)。但是为什么在这种情况下 gen_server 进程不退出。我不知道。
你能帮助我吗?非常感谢。 阮

ps:我认为棘手的部分可能在于rpc:multicall

4

1 回答 1

3

我认为这是因为 rpc:multicall 中生成的进程以 normal 的原因退出

当两个进程链接时,如果其中一个进程以normal的原因退出,则另一个没有 trap_exit 的进程将不存在。

而当process_flag(trap_exit, true)没有注释的时候,在gen_server.erl的源码中,我们可以看到:

346 decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
347     case Msg of
348         {system, From, Req} ->
349             sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
350                 [Name, State, Mod, Time], Hib);
351         {'EXIT', Parent, Reason} ->
352                 terminate(Reason, Name, Msg, Mod, State, Debug);

只要其父进程(生成 gen_server 的进程)退出,Gen_server 就会自动终止。

于 2013-07-27T05:39:02.143 回答