【问题标题】:Processes exiting normally进程正常退出
【发布时间】:2013-01-26 04:29:17
【问题描述】:

给定两个链接的进程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) 命令以防止孩子永远活着。 将start 中的ok. 更改为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 文档中的气味是什么意思?

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

【问题讨论】:

    标签: erlang signals


    【解决方案1】:

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

    所以:

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

    附:对不起我的英语

    附言spawn(fun() -&gt; 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})
    

    【讨论】:

    • 我明白了。感谢您的明确解释。建议的解决方案有效。我真的不明白为什么 shell 会这样工作,但这就是我想的那样;)。
    【解决方案2】:

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

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

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

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

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

    还有一点:当 start 函数执行 spawn_link 时,您通常将其称为 start_link。假设 start 函数只是 spawn 一个进程。当然,这只是一个约定,但很常见,所以你没有犯错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2013-07-03
      • 2022-10-16
      • 2014-06-09
      • 1970-01-01
      • 2020-11-04
      相关资源
      最近更新 更多