进程正常退出

时间:2013-01-25 04:44:09

标签: erlang signals

鉴于两个关联流程childparent,流程child如何检测parent正常退出(终止)?

作为一个绝对的Erlang初学者,我认为当一个进程没有别的办法时,就会使用exit(normal)退出。然后,这会发出所有链接过程的信号,其中

  • trap_exit设置为false的流程的行为是忽略该信号,
  • trap_exit设置为true的进程的行为是生成消息{'EXIT', pid, normal},其中pid是终止进程的进程ID。

我之所以认为这是Learn You Some Erlang for Great GoodErlang documentation表示以下内容。

  

如果退出原因是原子正常,则称一个过程正常终止。没有更多代码执行的进程会正常终止。

显然这是错误的(?),因为exit(normal)在命令提示符中显示** exception exit: normal并使下面的代码工作。退出是因为没有更多的代码可以执行,不会生成异常,也不会使我的代码工作。

例如,请考虑以下代码。

-module(test).
-export([start/0,test/0]).

start() ->
     io:format("Parent (~p): started!\n",[self()]),
     P = spawn_link(?MODULE,test,[]),
     io:format(
        "Parent (~p): child ~p spawned. Waiting for 5 seconds\n",[self(),P]),
     timer:sleep(5000),
     io:format("Parent (~p): dies out of boredom\n",[self()]),
     ok. 

test() ->
     io:format("Child (~p): I'm... alive!\n",[self()]),
     process_flag(trap_exit, true),
     loop().

loop() ->
     receive
          Q = {'EXIT',_,_} ->
                io:format("Child process died together with parent (~p)\n",[Q]);
          Q ->
                io:format("Something else happened... (~p)\n",[Q])
     after
          2000 -> io:format("Child (~p): still alive...\n", [self()]), loop()
     end.

这会产生如下输出。

(erlide@127.0.0.1)> test:start().
Parent (<0.145.0>): started!
Parent (<0.145.0>): child <0.176.0> spawned. Waiting for 5 seconds
Child (<0.176.0>): I'm... alive!
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Parent (<0.145.0>): dies out of boredom
ok
(erlide@127.0.0.1)10> Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
exit(pid(0,176,0),something).
Child process died together with parent ({'EXIT',<0.194.0>,something})

如果必须手动执行exit(pid(0,176,0),something)命令以防止孩子永远活着。 将ok.中的start更改为exit(normal)会使执行变得像这样

(erlide@127.0.0.1)3> test:start().
Parent (<0.88.0>): started!
Parent (<0.88.0>): child <0.114.0> spawned. Waiting for 5 seconds
Child (<0.114.0>): I'm... alive!
Child (<0.114.0>): still alive...
Child (<0.114.0>): still alive...
Parent (<0.88.0>): dies out of boredom
Child process died together with parent ({'EXIT',<0.88.0>,normal})
** exception exit: normal

我的具体问题如下。

  1. 如何使上述代码按预期工作。也就是说,如何确保子进程与父进程一起消失而不更改父进程
  2. 为什么exit(normal)在CLI中生成** exception exit: normal?我很难将异常视为正常的事情。 Erlang文档中的内容是什么意思?
  3. 我认为这些必须是非常基本的问题,但我似乎无法弄清楚这一点...... 我在Windows(x64)上使用Erlang 5.9.3.1。

2 个答案:

答案 0 :(得分:4)

Erlang shell具有用于将命令评估为单独进程的worker,并且您键入的所有命令都由同一进程运行。当你的start函数完成后,worker仍处于活动状态,当你通过exit()终止它时,shell理解为worker异常(因为worker在正常情况下永远不会死)。

所以:

  1. 您应该按spawnspawn_link
  2. 作为单独的流程运行
  3. CLI将所有工作人员出口记录为例外且正常
  4. P.S。对不起我的英文

    P.P.S。 spawn(fun() -> test:start() end).按预期工作

    4> spawn(fun() -> test:start() end).
    Parent (<0.41.0>): started!
    <0.41.0>
    Parent (<0.41.0>): child <0.42.0> spawned. Waiting for 5 seconds
    Child (<0.42.0>): I'm... alive!
    Child (<0.42.0>): still alive...
    Child (<0.42.0>): still alive...
    Parent (<0.41.0>): dies out of boredom
    Child process died together with parent ({'EXIT',<0.41.0>,normal})
    

答案 1 :(得分:2)

对@PetrKozorezov的答案的问题发表评论。 shell没有任何特殊行为。 shell工作进程只是一个正常的进程,所以如果它链接到的任何进程崩溃,那么它也会崩溃。然后将启动另一个工作进程。这是正常的 Erlang方式

您的start/0 功能只会返回并且 NOT 终止其进程,它只会输出“无聊的死亡”消息。这就是为什么循环继续前进,它没有得到exit信号,因为没有进程死亡。

当您将start/0函数更改为以exit(normal) 然后结束时,您会终止shell进程,以便向循环进程发送exit信号然后获取{'EXIT',...,...}消息并死亡。

当@PetrKozorezov在一个单独的进程中产生你的原始start/0函数,然后在执行start/0后它就死了,它向循环进程发送了一个退出normal信号,导致它死亡。 / p>

这是完全正常的Erlang行为和风格。您通常会使用exit结束启动功能,但会将其留给调用者以决定何时死亡。

还有一点:由于启动功能执行spawn_link,您通常会将其称为start_link。假设start函数仅为spawn进程。当然,这只是一个惯例,但却是一个常见的惯例,所以你没有犯错误。