为什么我不能杀死 Erlang 进程?

Why i can't kill Erlang process?

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

无法终止 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

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

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

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

如果真的要杀进程,使用kill原因:

exit(whereis(restarter), kill).

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


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