鉴于两个关联流程child
和parent
,流程child
如何检测parent
正常退出(终止)?
作为一个绝对的Erlang初学者,我认为当一个进程没有别的办法时,就会使用exit(normal)
退出。然后,这会发出所有链接过程的信号,其中
trap_exit
设置为false
的流程的行为是忽略该信号,trap_exit
设置为true
的进程的行为是生成消息{'EXIT', pid, normal}
,其中pid
是终止进程的进程ID。 我之所以认为这是Learn You Some Erlang for Great Good,Erlang 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
我的具体问题如下。
exit(normal)
在CLI中生成** exception exit: normal
?我很难将异常视为正常的事情。 Erlang文档中的内容是什么意思?我认为这些必须是非常基本的问题,但我似乎无法弄清楚这一点...... 我在Windows(x64)上使用Erlang 5.9.3.1。
答案 0 :(得分:4)
Erlang shell具有用于将命令评估为单独进程的worker,并且您键入的所有命令都由同一进程运行。当你的start
函数完成后,worker仍处于活动状态,当你通过exit()终止它时,shell理解为worker异常(因为worker在正常情况下永远不会死)。
所以:
spawn
或spawn_link
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
进程。当然,这只是一个惯例,但却是一个常见的惯例,所以你没有犯错误。