【问题标题】:GenServer doesn't trap_exit when started with start_link使用 start_link 启动时,GenServer 不会 trap_exit
【发布时间】:2019-10-04 09:34:08
【问题描述】:

我发现当尝试捕获退出信号时,使用 GenServer.start 然后 Process.link 启动 GenServer 的 pid 与运行 GenServer.start_link 的结果截然不同。

这是我用来演示问题的实验代码:

defmodule Foo do
  defmodule Server do
    def init(_) do
      Process.flag(:trap_exit, true)
      {:ok, nil}
    end
    def handle_info({:EXIT, from, reason}, _) do
      IO.inspect({:kill_signal, from, reason})
      {:noreply, nil}
    end
  end

  def foo() do
    Process.flag(:trap_exit, true)
    # version 1
    {:ok, pid} = GenServer.start_link(Server, nil)

    # version 2
    # {:ok, pid} = GenServer.start(Server, nil)
    # Process.link(pid)

    # print process info
    IO.inspect({self(), pid, Process.info(pid)})

    Process.exit(pid, :reason)

    :timer.sleep(200)
  end
end

Foo.foo

对于版本 1,EXIT 信号会导致 Server 退出而不会被其 handle_info 块捕获,但对于版本 2,信号在 handle_info 块中被正确拦截和处理,因此 Server没有终止。我还注意到这两种启动 GenServer 的方式中的Process.info 是相同的。

我对@9​​87654331@ 和spawn 进行了同样的尝试,但它们的行为都符合预期——EXIT 信号全部被捕获——没有区别:

defmodule Foo do
  def loop do
    Process.flag(:trap_exit, true)
    receive do
      msg -> IO.inspect(msg)
    end
    loop
  end

  def foo() do
    Process.flag(:trap_exit, true)
    # version 1
    pid = spawn_link(&loop/0)

    # version 2
    # pid = spawn(&loop/0)
    # Process.link(pid)

    # print process info
    IO.inspect({self(), pid, Process.info(pid)})

    Process.exit(pid, :reason)

    :timer.sleep(200)
  end
end

Foo.foo

顺便说一句,如果重要的话,我在 Erlang/OTP 21 上使用 Elixir 1.8.1。

我想知道导致行为差异的原因是什么,这是一个错误还是设计使然,以及如果我想以原子方式调用 start+link,如何正确捕获 EXIT。

【问题讨论】:

标签: erlang elixir erlang-otp gen-server


【解决方案1】:

handle_info 没有被调用,因为发送退出信号的是父进程。 GenServer 和所有其他行为处理父级退出信号并且总是在父级退出时关闭,主要是因为如果你在监督树中并且你的监督员关闭了,你也想立即终止,因为那一刻所有的赌注都没有了。如果你替换这个:

Process.exit(pid, :reason)

作者:

spawn fn -> Process.exit(pid, :reason) end

您可以看到handle_info 被调用,因为另一个进程正在发送退出信号。

【讨论】:

猜你喜欢
  • 2017-02-17
  • 2018-06-30
  • 2015-07-27
  • 2017-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-12
相关资源
最近更新 更多