3

2 つのリンクされたプロセスchildとが与えられた場合、プロセスは正常に終了 (終了)したことをparentどのようにchild検出しますか?parent

Erlang の完全な初心者である私は、他に何もすることがないプロセスは、 を使用して終了すると考えていましたexit(normal)。これにより、リンクされたすべてのプロセスが通知されます。

  • trap_exitに設定されているプロセスの動作はfalse、シグナルを無視することです。
  • trap_exitに設定されているプロセスの動作は、終了プロセスのプロセス ID であるメッセージtrueを生成することです。{'EXIT', pid, normal}pid

私がこれを考える理由は、Learn You Some Erlang for Great Goodと、Erlang のドキュメントに次のように記載されているためです。

終了理由がアトムの正常な場合、プロセスは正常に終了したと言われます。実行するコードがなくなったプロセスは、正常に終了します。

コマンドプロンプトに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.するstartexit(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 シェルには、コマンドを評価するためのワーカーが別のプロセスとしてあり、入力したすべてのコマンドが同じプロセスによって実行されます。関数が終了したときstart、ワーカーはまだ生きていて、exit() でそれを強制終了すると、シェルはワーカー例外として認識します (通常、ワーカーは死ぬことはないため)。

そう:

  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の回答に対するあなたの質問へのコメント。シェルは特別な動作をしていません。シェルワーカープロセスは通常のプロセスであるため、リンクされているプロセスがクラッシュすると、それもクラッシュします。その後、別のワーカープロセスが開始されます。これは通常のErlangの方法です。

関数は単に戻り、プロセスを終了せず、「退屈の死」メッセージを出力するだけですstart/0 そのため、ループは続行され、プロセスが停止していないため、シグナルは取得されません。exit

start/0関数をで終了するようexit(normal) 変更すると、シェルプロセスが終了するため、exitシグナルがループプロセスに送信され、ループプロセスが{'EXIT',...,...}メッセージを取得して終了します。

@PetrKozorezovが元のstart/0関数を別のプロセスで生成し、実行後に停止すると、ループプロセスにstart/0終了信号が送信され、関数が停止しました。normal

これは完全に正常なErlangの動作とスタイルです。通常、 start関数をで終了することはありませんが、いつ終了するかを決定するのは呼び出し元に任せます。exit

もう1つの小さなポイント:start関数がspawn_link実行するので、通常はstart_link代わりにそれを呼び出します。start関数は単なるspawnプロセスと見なされます。もちろん、これは単なる慣例ですが、一般的なものなので、間違いはありません。

于 2013-01-25T20:29:17.687 に答える