【问题标题】:Why i can't kill Erlang process?为什么我不能杀死 Erlang 进程?
【发布时间】:2020-01-10 16:13:06
【问题描述】:

我正在生成 2 个进程,似乎我无法杀死其中任何一个:

  • restarter - 每当它出现故障时都会产生 worker 的进程
  • worker - 从 shell 获取消息的进程,将它们连接起来并在退出的 reason 中返回它们到重启程序,然后将它们转发到 shell。

worker 进程不能被杀死,因为restarter 会在任何陷阱退出消息上重新启动它。但是是什么让restarter 进程保持活力?

-module(mon).
-compile_flags([debug_info]).
-export([worker/1,init/0,restarter/2,clean/1]).

% ctrl+g
init()->
    Pid=spawn(?MODULE,restarter,[self(),[]]),
    register(restarter,Pid),
    Pid.


restarter(Shell,Queue)->
    process_flag(trap_exit,true),

    Wk=spawn_link(?MODULE,worker,[Queue]),
    register(worker,Wk),

    receive

        {'EXIT',Pid,{Queue,normal}}->Shell ! {Queue,"From res: worker died peacefully, wont restart"};

        {'EXIT',Pid,{Queue,horrible}} ->
                Shell ! {Queue,"Processed so far:"},
            Shell ! "will restart in 5 seconds, select fresh/stale -> 1/0",
            receive
                1 -> 
                    Shell ! "Will restart fresh",
                    restarter(Shell,[]);
                0 ->Shell ! "Will continue work",
                    restarter(Shell,Queue)
            after 5000 ->
              Shell ! "No response -> started with 666",
              restarter(Shell,[666]) 
            end;
        {MSG}->Shell ! {"Unknown message...closing",MSG}
end.


worker(Queue)->

    receive 
        die->exit({Queue,horrible});
        finish->exit({Queue,normal});
        MSG->worker([{time(),MSG}|Queue])
    end.

用法

mon:init().
regs().  %worker and restarter are working
whereis(worker) ! "msg 1", whereis(worker) ! "msg2".
whereis(worker) ! finish.
flush().  % should get the first clause from restarter 
regs().  % worker should be up and running again
exit(whereis(restarter),reason).
regs().  % restarter should be dead

【问题讨论】:

    标签: process erlang exit


    【解决方案1】:

    在这种情况下,restarter 进程正在捕获出口,因此exit(whereis(restarter), reason) 不会杀死它。退出信号被转换为消息,并被放入进程的消息队列中:

    > process_info(whereis(restarter), messages).
    {messages,[{'EXIT',<0.76.0>,reason}]}
    

    它仍在消息队列中的原因是receive 表达式中的所有子句都与此消息不匹配。前两个子句特定于worker 进程使用的退出原因,最后一个子句可能看起来像一个包罗万象的子句,但实际上并非如此——它匹配任何带有一个元素的元组的消息。如果写成MSG 而不是{MSG},它会收到退出原因消息,并向shell 发送“未知消息”。

    如果你真的想杀死进程,使用kill原因:

    exit(whereis(restarter), kill).
    

    kill 退出信号是不可捕获的,即使进程正在捕获退出。


    另一件事:前两个接收子句只有在工作队列为空时才会匹配。那是因为它重用了变量名Queue,所以{'EXIT',Pid,{Queue,normal}} 中的队列必须等于作为参数传递给restarter 函数的值。在这种情况下,您通常会使用NewQueue 或其他东西作为接收子句中的变量。

    【讨论】:

    • 但是从LYAE阅读我了解到exit/2被用作杀死进程的触发器。我不明白,你只能用kill杀死进程作为reason在什么时候使用exit/2 ?
    • 只要你试图杀死的进程没有捕获出口,它就可以正常工作。
    猜你喜欢
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 2023-04-08
    相关资源
    最近更新 更多