1

来自这里的简短副本:

exit(Pid, Reason) -> true

类型:

Pid =pid() 原因 =term()

Reason向进程发送带有退出原因的退出信号Pid

normal如果 Reason 是除or之外的任何术语,则以下行为适用kill

如果Pidis not trapping exits,Pid它本身会以 exit reason 退出Reason。如果Pid是捕获出口,则出口信号被转换为消息{'EXIT', From, Reason}并传递到 的消息队列中PidFrom是发送退出信号的进程的 pid。另请参阅process_flag/2

如果Reason是 atom normalPid则不会退出。如果它正在捕获出口,则出口信号将转换为消息{'EXIT', From, normal}并传递到其消息队列。

IfReason是 atom kill,即 ifexit(Pid, kill)被调用,将发送一个不可捕获的退出信号,该信号Pid将无条件退出并带有 exit reason killed

当用作 a和as a时,我正在玩弄该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>

不应该是只向shell进程发送“正常”退出消息,所以没有理由退出吗?

相似地:

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 ( shell.erl ) 处理'EXIT'类型消息的normal方式与其他退出消息没有任何不同,这意味着它会发送错误并重新启动 shell。如果您真的想知道这一点,您可以使用调试器以这种方式跟踪程序流程:

  1. 下载shell.erl
  2. 将文件名更改为shell2.erl
  3. 打开文件并将模块名称也更改shell2为。您需要这样做,因为编译器会抱怨shell位于粘性目录中。
  4. 启动erl提示。
  5. c(shell2, [debug_info]).
  6. debugger:start().
  7. Module -> Interpret并选择 shell2.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() 发送消息),信号满足第二种情况get_command1/5,它将首先给出错误消息,并产生一个新的 shell pid。请注意start_eval功能。

对于您的第二种情况(向 spawn 发送消息pid),回到您关于该exit功能的帖子的第一部分,这是合乎逻辑的。您生成pid的不会捕获退出消息,并忽略该(normal) exit消息。因此只有在您的 spawn实际退出shell时才会收到退出消息。pid它将进入 的第一个条件get_command1/5。因为start_evel没有被调用,所以shell pid会保持不变。

对于你的第三种情况,我不知道为什么。我也认为is_process_alive(v(8))应该返回true。

于 2012-11-19T20:47:14.690 回答
1

正如您的第三个示例所示,如果任何进程执行exit(self(), normal)然后它会崩溃,而exit(AnotherPid, normal)不会导致其他进程崩溃。我已经在 R15B 上验证了它。我个人认为这是一个错误,因为向任何进程发送退出信号normal不应导致其崩溃。

于 2012-11-20T15:32:35.877 回答
0

对于第三种情况,这里的关键点是 self() 是衍生进程的 pid,而不是 shell 的。

见下面的代码:

Eshell V5.9  (abort with ^G)

1> 自我()。

<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))。

错误的

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 回答