1

ここからの短いコピー:

exit(Pid, Reason) -> true

タイプ:

Pid=pid() 理由=term()

終了理由を含む終了信号をReasonプロセスに送信しますPid

次の動作は、理由がまたは以外の用語である場合に適用されnormalますkill

Pidが出口をトラップしていない場合、Pidそれ自体が出口理由で終了しますReason。が出口をトラップしている場合Pid、出口信号はメッセージに変換され{'EXIT', From, Reason}、のメッセージキューに配信されますPidFrom終了信号を送信したプロセスのpidです。も参照してくださいprocess_flag/2

Reasonがアトムの場合normalPid終了しません。出口をトラップしている場合、出口信号はメッセージに変換され、{'EXIT', From, normal}そのメッセージキューに配信されます。

Reasonがアトムの場合kill、つまりexit(Pid, kill)が呼び出された場合、トラップできない終了信号が送信されPid、終了理由で無条件に終了しますkilled

として使用した場合のexit/2関数とその動作を試してみました。self()PidnormalReason

Erlang R15B03 (erts-5.9.3) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.3  (abort with ^G)
1> self().
<0.32.0>
2> exit(self(), normal).
** exception exit: normal
3> self().
<0.35.0>

「通常の」終了メッセージのみがシェルプロセスに送信されるので、終了する理由がないというのは事実ではないでしょうか。

同様に:

4> spawn(fun() -> receive Pid -> Pid ! ok end end). 
<0.38.0>
5> exit(v(4), normal).
true
6> v(4) ! self().
<0.35.0>
7> flush().
Shell got ok
ok

だが:

8> spawn(fun() -> exit(self(), normal), receive _ -> ok end end).         
<0.43.0>
9> is_process_alive(v(8)).
false
4

5 に答える 5

3

Erlangシェル(shell.erl )は、他の終了メッセージとは異なる'EXIT'タイプのメッセージを処理しないようです。つまり、エラーを送信してシェルを再起動します。normalこれを本当に知りたい場合は、次のようにデバッガーを使用してプログラムフローをトレースできます。

  1. shell.erlをダウンロード
  2. ファイル名をに変更しますshell2.erl
  3. ファイルを開き、モジュール名もに変更しますshell2shellコンパイラがスティッキーディレクトリにあることについて文句を言うので、これを行う必要があります。
  4. プロンプトを開始しerlます。
  5. c(shell2, [debug_info]).
  6. debugger:start().
  7. Module -> Interpretshell2.erlを選択します
  8. shell2:start().
  9. トレースアウェイ!
于 2012-11-19T20:36:12.890 に答える
1

その理由はソースコード「stdlib-1.18.2/src/shell.erl」からわかると思います。

get_command(Prompt, Eval, Bs, RT, Ds) ->
    Parse = fun() -> exit(io:parse_erl_exprs(Prompt)) end,
    Pid = spawn_link(Parse),
    get_command1(Pid, Eval, Bs, RT, Ds).

get_command1(Pid, Eval, Bs, RT, Ds) ->
    receive
    {'EXIT', Pid, Res} ->
        {Res, Eval};
    {'EXIT', Eval, {Reason,Stacktrace}} ->
            report_exception(error, {Reason,Stacktrace}, RT),
        get_command1(Pid, start_eval(Bs, RT, Ds), Bs, RT, Ds);
    {'EXIT', Eval, Reason} ->
            report_exception(error, {Reason,[]}, RT),
        get_command1(Pid, start_eval(Bs, RT, Ds), Bs, RT, Ds)
    end.

report_exception(Class, Reason, RT) ->
    report_exception(Class, serious, Reason, RT).

report_exception(Class, Severity, {Reason,Stacktrace}, RT) ->
    Tag = severity_tag(Severity),
    I = iolist_size(Tag) + 1,
    PF = fun(Term, I1) -> pp(Term, I1, RT) end,
    SF = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
    io:requests([{put_chars, Tag},
                 {put_chars, 
                  lib:format_exception(I, Class, Reason, Stacktrace, SF, PF)},
                 nl]).

start_eval(Bs, RT, Ds) ->
    Self = self(),
    Eval = spawn_link(fun() -> evaluator(Self, Bs, RT, Ds) end), %%<========start a new shell pid
    put(evaluator, Eval),
    Eval.

severity_tag(fatal)   -> <<"*** ">>;
severity_tag(serious) -> <<"** ">>;
severity_tag(benign)  -> <<"* ">>.

最初のケース(self()にメッセージを送信)の場合、シグナルはの2番目の状況を満たし、get_command1/5最初にエラーメッセージを表示し、新しいシェルpidを生成します。機能にご注意くださいstart_eval

2番目のケース(スポーンにメッセージを送信するpid)の場合、関数に関する投稿の最初の部分に戻るとexit、それは論理的です。スポーンpidされたメッセージは終了メッセージをトラップせず、(normal) exitメッセージを無視します。そのため、スポーンが実際に終了shellしたときにのみ終了メッセージを受け取ります。pidの第1条件になりget_command1/5ます。start_evel呼び出されないのでshell pid、同じままにします。

3番目のケースでは、理由がわかりません。私もis_process_alive(v(8))真に戻るべきだと思います。

于 2012-11-19T20:47:14.690 に答える
1

3番目の例が示すように、いずれかのプロセスが実行するexit(self(), normal)とクラッシュしますが、実行exit(AnotherPid, normal)すると他のプロセスはクラッシュしません。R15Bで確認しました。個人的には、これはバグだと思います。どのnormalプロセスにも終了シグナルを送信しても、プロセスがクラッシュすることはないはずだからです。

于 2012-11-20T15:32:35.877 に答える
0

3番目のケースの場合、ここで重要な点は、self()がシェルではなく生成されたプロセスのpidであるということです。

以下のコードを参照してください。

Eshell V5.9  (abort with ^G)

1> self()。

<0.32.0>

2> spawn(fun()-> io:format( "This is〜p〜n"、[self()])、exit(self()、normal)、receive _-> ok end end)。

これは<0.35.0><0.35.0>です

3> is_process_alive(v(2))。

false

4>

于 2012-11-20T07:35:02.927 に答える
0

あなたが引用したドキュメントにはそれで大丈夫です:

If Pid is not trapping exits, Pid itself will exit with exit reason Reason.

出口をトラップしないと、プロセスは終了します。

1> self().
<0.32.0>
2> process_flag(trap_exit, true).
false
3> exit(self(), normal).
true
4> self().
<0.32.0>
5> flush().             
Shell got {'EXIT',<0.32.0>,normal}
ok

出口をトラップしない場合、出口について送信される「メッセージ」はありません。プロセスはただ死にます。それにリンクされているプロセスも同様です。これがtrap_exit目的です。

于 2012-11-28T18:05:53.217 に答える