【问题标题】:Can't get a gen_server to crash from a spawn_linked process crash无法让 gen_server 从 spawn_linked 进程崩溃中崩溃
【发布时间】:2009-08-14 22:02:53
【问题描述】:

根据我在文档中阅读的内容,gen_servers 不会捕获出口。此外,我的理解是,如果一个进程使用 spawn_link 启动另一个进程,并且子进程崩溃,则父进程也会崩溃。

但是,这不是我所看到的。我有一个生成链接进程的 gen_server。我在子进程中设置了一个函数,如下所示:

test(JobIsHalfDone) -> 
    case JobIsHalfDone of
        true -> exit(test);
        false -> ok
    end.

当这个函数发送退出信号时,我收到一条消息:

** 异常退出:测试

然而它的父 gen_server 一直在滴答作响。为什么?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    让我们比较一下经验,我有以下行为表明当链接进程死亡时它确实会死亡。

    1> {ok, Pid} = gen_server:start(server, [], []).
    {ok,<0.33.0>}
    2> gen_server:call(Pid, nice_to_see_you).
    thanks
    3> gen_server:call(Pid, nice_to_see_you).
    thanks
    4> gen_server:call(Pid, twap).           
    oh_noes
    5> gen_server:call(Pid, nice_to_see_you).
    ** exception exit: {noproc,{gen_server,call,[<0.33.0>,nice_to_see_you]}}
         in function  gen_server:call/2
    

    也就是说,我通过 spawn_link:ing 一个没有太多作用但正在死亡的进程使其崩溃,从而导致服务器停机。

    -module(server).
    -compile(export_all).
    init(_) ->
      {ok, []}.
    handle_call(twap, _From, State) ->
       spawn_link(fun suicidal/0),
       {reply, oh_noes, State};
    handle_call(_, _From, State) ->
       {reply, thanks, State}.
    suicidal() ->
       exit(kaboom).
    

    您看到“*** exception exit: test”这一事实似乎表明您从 shell 中使用了 gen_server:start_link/3,因此您的 gen server 链接到了 shell 进程。这可能会带来额外的混乱,但无法解释为什么您会认为服务器没有死。

    【讨论】:

    • 是的,你是对的。我自己只是用最小的 gen_server 验证了它。我真正的 gen_server 中一定有其他事情发生。
    • 想通了。我已将 spawn_link 松散地放置在 gen_server 模块中,而不是将其作为回调包含在内。显然这破坏了 gen_server 抽象。
    • 那么你需要什么才能将答案作为最终答案?
    • 我认为我没有足够的声誉。
    【解决方案2】:

    我认为您的 spawn_linked 进程的上下文是进行调用的进程,而不是 gen_server。要么在 init() 回调中生成循环,要么执行 gen_server:call() 并在 handle_call 中生成循环。然后循环将链接到运行 gen_server 的进程。

    【讨论】:

      【解决方案3】:

      我错了,我想这让我更接近于理解为什么它没有杀死我的真实服务器。

      -module(crash).
      -behaviour(gen_server).
      
      -export([start_link/0]).
      
      -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
           terminate/2, code_change/3]).
      
      -export([crash/0]).
      
      start_link() ->
          gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
      
      init([]) ->
          {ok, []}.
      
      crash() ->
          gen_server:cast(?MODULE, crash).
      
      handle_call(_Request, _From, State) ->
          Reply = ok,
          {reply, Reply, State}.
      
      handle_cast(crash, State) ->
          spawn_link(fun() ->
                         crash_loop(0)
                 end),
          {noreply, State};
      handle_cast(_Msg, State) ->
          {noreply, State}.
      
      handle_info(_Info, State) ->
          {noreply, State}.
      
      terminate(_Reason, _State) ->
          ok.
      
      code_change(_OldVsn, State, _Extra) ->
          {ok, State}.
      
      crash_loop(Counter) ->
          case Counter =:= 10 of
          true ->
              exit(crash_loop);
          false ->
              ok
          end,
          timer:sleep(100),
          crash_loop(Counter + 1).
      

      ...在 shell 中测试:

      11> c(crash).
      {ok,crash}
      12> crash:start_link().
      {ok,<0.67.0>}
      13> crash:crash().
      ok
      14> ** exception error: crash_loop
      14> whereis(crash).
      undefined
      

      【讨论】:

        猜你喜欢
        • 2021-03-28
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 2019-05-03
        • 1970-01-01
        • 2011-08-17
        • 2011-03-16
        • 2015-12-21
        相关资源
        最近更新 更多