0

我有两个 gen_server 模块。
第一个服务器.erl

-module(serv).
-behaviour(gen_server).
-export([init/1, 
     handle_call/3,
     handle_cast/2, 
     handle_info/2,
     code_change/3,
     terminate/2,
     start_link/0
    ]).
start_link() ->
    gen_server:start_link(?MODULE, [], []).

init([]) ->
    process_flag(trap_exit, true),
    spawn_link(user, start_link,[]),
    {ok, []}.

handle_call(_E, _From, State) ->
        {noreply, State}.

handle_cast(_Message, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

handle_info(Message, State) ->
    {noreply, State}.

code_change(_OldVersion, State, _Extra) ->
    {ok, State}.

user.erl(除了 init/1 完全一样):

init([]) ->
     {ok, []}.

我以为服务器会永远存在。如果第一台服务器死机,另一台服务器会收到{'EXIT', Pid, Reason}消息。

但是如果您通过serv:start_link()启动模块,用户模块将在启动后立即退出并显示消息{'EXIT',Pid,normal}用户为什么会死?

4

2 回答 2

5

spawn并且spawn_link是用于启动新进程的两个基本 Erlang 函数。spawn两者都将创建一个进程,然后使用/的参数中指定的参数调用函数spawn_link当该函数结束时,进程会自动以退出原因终止normal功能之间的区别在于,spawn_link它还创建了两个进程之间的链接。

gen_server:start_link函数所做的不仅仅是通过启动行为然后运行提供所有行为功能的行为顶部循环来创建流程。除其他事项外,回调函数init被调用以初始化行为,然后返回{ok,State}以告诉行为一切都已初始化并且进展顺利,这是传递给所有回调的本地状态。gen_server 的回调函数不是直接调用而是通过行为调用。

因此,当您显式生成一个仅运行该init函数的进程时,它将在该init函数结束后立即终止。这就是这里发生的事情。

{'EXIT',Pid,Reason}消息来自被链接的进程,并且该进程正在捕获出口。当一个进程终止时,退出信号会从终止进程发送到它所链接的所有进程。当此信号到达进程捕获出口时,它会转换为正常消息并放入该进程的消息队列中。这就是你在这里看到的。请注意,由于链接和陷阱出口,所有这些都是自动完成的。

我希望这会有所帮助。很抱歉在这里有点过度说教。

于 2013-07-25T22:28:53.083 回答
3

当您使用 spawn 链接功能时,您将启动一个新进程,该进程调用user:start_link. 该进程启动并链接到用户 gen_server 进程,然后退出,因为调用user:start_link返回。用户进程链接到该进程,因此它会收到退出信号。由于用户进程没有捕获退出,它也退出了。

您应该按照评论中的建议在user:start_link您的serv:init函数中运行。

于 2013-07-25T18:27:47.410 回答