无法让 gen_server 因 spawn_linked 进程崩溃而崩溃

发布于 2024-08-02 01:11:29 字数 396 浏览 5 评论 0原文

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

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

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

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

** 异常退出:测试

但其父 gen_server 仍保持正确状态。 为什么?

From what I've read in the docs, gen_servers don't trap exits. Moreover, my understanding is that if a process starts another process with spawn_link, and the child process crashes, the parent crashes too.

However, this is not what I'm seeing. I've got a gen_server that spawn_links a process. I set up a function in the child process like so:

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

When this function sends the exit signal, I get a message:

** exception exit: test

Yet its parent gen_server keeps right on ticking. Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

辞慾 2024-08-09 01:11:29

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

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).

事实上,您看到“***异常退出:测试”似乎表明您从shell中使用了gen_server:start_link / 3,因此您的gen服务器链接到了shell进程。 这可能会带来额外的混乱,但没有任何解释为什么你会认为服务器没有死掉。

Lets compare experience, I have the following behaviour that says that it does die when a linked process dies.

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

That is, I made it crash by spawn_link:ing a process that does not much but dying, bringing the server down with it.

-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).

The fact that you see the "*** exception exit: test" seems to indicate that you used gen_server:start_link/3 from the shell, so that you gen server is linked to the shell process. That might introduce additional confusion, but nothing explaining why you would think the server didnt die.

海的爱人是光 2024-08-09 01:11:29

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

I think the context of your spawn_linked process is the process that made the call, not the gen_server. Either spawn the loop in the init() callback or do a gen_server:call() and spawn the loop in a handle_call. Then the loop will be linked to the process that is running the gen_server.

随梦而飞# 2024-08-09 01:11:29

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

-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

I was wrong, which I guess leaves me a step closer to understanding why it's not killing my real server.

-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).

...and testing in 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文