无监督的gen_server在收到退出信号时不会调用终止

Maj*_*imi 5 erlang erlang-otp gen-server

gen_serverModule:terminate回调文档说:

即使gen_server进程不是监督树的一部分,如果它从其父进程收到"EXIT"消息,也会调用此函数.原因与"退出"消息中的相同.

这是我handle_infoterminate功能:

handle_info(UnknownMessage, State) ->
    io:format("Got unknown message: ~p~n", [UnknownMessage]),
    {noreply, State}.

terminate(Reason, State) ->
    io:format("Terminating with reason: ~p~n", [Reason]).
Run Code Online (Sandbox Code Playgroud)

我使用启动此服务器gen_server:start.我假设我打电话erlang:exit(Pid, fuckoff)时应该调用terminate回调函数.但它显示:

Got unknown message: {'EXIT',<0.33.0>,fuckoff}
Run Code Online (Sandbox Code Playgroud)

这意味着它在呼唤handle_info.但是当我打电话时gen_server:stop,一切都按照文档中的说明进行.我是gen_server从shell 调用我的.你能澄清一下吗?

[UPDATE]

decode_msg里面函数的源代码gen_server.如果它收到任何'EXIT'消息,它应该调用terminate函数:

decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
    case Msg of
    {system, From, Req} ->
        sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
                  [Name, State, Mod, Time], Hib);
    {'EXIT', Parent, Reason} ->
        terminate(Reason, Name, Msg, Mod, State, Debug);
    _Msg when Debug =:= [] ->
        handle_msg(Msg, Parent, Name, State, Mod);
    _Msg ->
        Debug1 = sys:handle_debug(Debug, fun print_event/3,
                      Name, {in, Msg}),
        handle_msg(Msg, Parent, Name, State, Mod, Debug1)
end.
Run Code Online (Sandbox Code Playgroud)

在我的情况下,它不会调用terminate函数.

[UPDATE]

当我开始gen_server使用时gen_server:start_link(),使用发送退出信号erlang:exit(Pid, Reason)将导致terminate调用回调函数,这是预期的行为.似乎在解释退出信号方面存在差异,无论进程是否与其父进程相关联.

Ham*_*ani 3

简短回答:

exit/2如果您从 actor 内部调用该函数gen_server,它将根据文档按照预期运行,并且terminate/2将调用回调。

长答案:

当您从 shell 发送退出消息时,Parent退出元组的值将设置为 shell 进程 id,另一方面,当您从gen_servershell 启动进程时,其Parent值将设置为其自己的进程 id,而不是 shell 进程 id,因此,当它收到退出消息时,它与decode_msg/8函数中接收块的第二个子句不匹配,因此terminate/6不会调用该函数,最后匹配调用handle_msg/5函数的下一个子句。

推荐:

为了terminate/3即使通过向进程发送退出消息来调用回调gen_server,您可以捕获退出消息handle_info/2,然后使用停止元组返回,如下所示:

init([]) ->
    process_flag(trap_exit, true),
    {ok, #state{}}.

handle_info({'EXIT', _From, Reason}, State) ->
    io:format("Got exit message: ~p~n", []),
    {stop, Reason, State}.

terminate(Reason, State) ->
    io:format("Terminating with reason: ~p~n", [Reason]),
    %% do cleanup ...
    ok.
Run Code Online (Sandbox Code Playgroud)