3

给定两个链接的进程childparent,进程如何child检测到parent正常退出(终止)?

我,作为一个绝对的 Erlang 初学者,认为一个进程,当它无事可做时,使用exit(normal). 然后,这会向所有链接的进程发出信号,其中

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

我这么认为的原因是Learn You Some Erlang for Great GoodErlang 文档,其中说明了以下内容。

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

显然这是错误的 (?),因为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. 为什么会在 CLI中exit(normal)生成一个?** exception exit: normal我很难将异常视为正常现象。Erlang 文档中的气味是什么意思?

我认为这些一定是非常基本的问题,但我似乎无法弄清楚......我在 Windows (x64) 上使用 Erlang 5.9.3.1。

4

2 回答 2

4

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

所以:

  1. spawn您应该通过或作为单独的进程运行启动spawn_link
  2. CLI 将所有工作人员退出记录为异常和正常

PS对不起我的英语

PPSspawn(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})
于 2013-01-25T08:03:49.470 回答
2

在@PetrKozorezov 的回答中对您的问题发表评论。外壳并没有以任何方式表现特殊。shell worker 进程只是一个普通进程,所以如果它链接到的任何进程崩溃,那么它也会崩溃。然后将启动另一个工作进程。这是正常的Erlang 方式

您的start/0 函数只是返回并且不会终止其进程,它只是输出“无聊之死”消息。这就是为什么循环继续进行的原因,它没有收到exit信号,因为没有进程死亡。

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

当@PetrKozorezovstart/0在一个单独的进程中生成您的原始函数时,该函数在执行后死亡,start/0它向循环进程发送了一个退出normal信号,导致它死亡。

这是完全正常的 Erlang 行为和风格。您通常不会用 an结束start函数,exit而是让调用者决定何时结束。

还有一点:正如 start 函数所做的那样,spawn_link您通常会调用它start_link。假设一个start函数只是spawn一个过程。当然,这只是一个约定,而是一个常见的约定,因此您没有犯错误。

于 2013-01-25T20:29:17.687 回答