Erlang OTP 内部细节之gen_server

如果gen_server进程需要在死亡的时候调用terminate函数,则需要调用process_flag(trap_exit, true)设置为系统进程。但是什么时候需要在handle_info中处理{'EXIT', FROM, REASON}消息呢?我的观点是,如果我们在继承了gen_server的进程中关联了其他进程(不包括父进程,如supervisor进程),那么就需要在handle_info中捕获这条消息,如果只是和父进程关联(如supervisor进程)则不需要捕获该消息,因为在gen_server模块内自动捕获了来自父进程的{'EXIT', FROM, REASON}消息,gen_server处理消息的代码如下

decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
    case Msg of
    {system, From, get_state} ->
        sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
                  {State, [Name, State, Mod, Time]}, Hib);
    {system, From, {replace_state, StateFun}} ->
        NState = try StateFun(State) catch _:_ -> State end,
        sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
                  {NState, [Name, NState, Mod, Time]}, Hib);
    {system, From, Req} ->
        sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
                  [Name, State, Mod, Time], Hib);
    {'EXIT', Parent, Reason} -> %% 如果退出消息是父进程发送来的,则调用terminate消息
        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.

terminate消息处理如下:

terminate(Reason, Name, Msg, Mod, State, Debug) ->
    case catch Mod:terminate(Reason, State) of
    {'EXIT', R} ->
        error_info(R, Name, Msg, State, Debug),
        exit(R);
    _ ->
        case Reason of
        normal ->
            exit(normal);
        shutdown ->
            exit(shutdown);
        {shutdown,_}=Shutdown ->
            exit(Shutdown);
        _ ->
            FmtState =
            case erlang:function_exported(Mod, format_status, 2) of
                true ->
                Args = [get(), State],
                case catch Mod:format_status(terminate, Args) of
                    {'EXIT', _} -> State;
                    Else -> Else
                end;
                _ ->
                State
            end,
            error_info(Reason, Name, Msg, FmtState, Debug),
            exit(Reason)
        end
    end.

terminate/6函数只是调用了继承gen_server行为的termniate函数

posted @ 2014-03-05 11:34  wangjunshusheng  阅读(242)  评论(0)    收藏  举报