从内部杀死GenServer

Hai*_*ito 4 elixir

考虑这样简单的GenServer模块:

defmodule Crap do
  use GenServer

  ... #All the needed crap

  def handle_info(:kill_me_pls, state) do
    GenServer.stop(self)
    {:noreply, state}
  end

  def terminate(_, state) do
    IO.inspect "Look! I'm dead."
  end

end
Run Code Online (Sandbox Code Playgroud)

并考虑将这些表达式放入repl中:

{:ok, pid} = Crap.start_link

send_message_to_that_pid
Run Code Online (Sandbox Code Playgroud)

这是我的conceirns开始的地方,因为Process.alive? pid返回true,但是进程没有响应而且terminate没有被调用,尽管如果我GenServer.stop(pid)在'clean'进程中调用repl(没有收到kill消息)就可以正常杀死它.如果停止调用收到的进程:kill_me_pls消息挂起了repl.

Dog*_*ert 9

正确的做法应该停止GenServer"从内部"是返回一个{:stop, reason, new_state}由值handle_*{:stop, reason, reply, new_state}handle_call.您的代码失败的原因是调用GenServer.stop向GenServer发送特殊消息,并且由于GenServer是单个进程并且当前处于进程中handle_info,因此它无法响应该stop调用,因此您的进程挂起/创建死锁.

这是正确的方法:

def handle_info(:kill_me_pls, state) do
  {:stop, :normal, state}
end
Run Code Online (Sandbox Code Playgroud)

你可以阅读更多有关可能的返回值,检查出的标题下的文本Return valuesGenServer的文档.

演示:

iex(1)> defmodule Crap do
...(1)>   use GenServer
...(1)>
...(1)>   def handle_info(:kill_me_pls, state) do
...(1)>     {:stop, :normal, state}
...(1)>   end
...(1)>
...(1)>   def terminate(_, state) do
...(1)>     IO.inspect "Look! I'm dead."
...(1)>   end
...(1)> end
iex(2)> {:ok, pid} = GenServer.start Crap, []
{:ok, #PID<0.98.0>}
iex(3)> send(pid, :kill_me_pls)
"Look! I'm dead."
:kill_me_pls
iex(4)> Process.alive?(pid)
false
Run Code Online (Sandbox Code Playgroud)