here的简短副本:
exit(Pid, Reason) -> true
类型:
Pid =
pid()
原因=term()
将退出原因
Reason
的退出信号发送到流程Pid
。如果“原因”是除
normal
或kill
以外的任何字词,则会应用以下行为:如果
Pid
没有捕获退出,则Pid
本身将以退出原因Reason
退出。如果Pid
正在捕获退出,则退出信号将转换为消息{'EXIT', From, Reason}
并传递到Pid
的消息队列。From
是发送退出信号的进程的pid。另请参阅process_flag/2
。如果
Reason
是原子normal
,Pid
将不会退出。如果它正在捕获退出,则退出信号将转换为消息{'EXIT', From, normal}
并传递到其消息队列。如果
Reason
是原子kill
,即如果调用了exit(Pid, kill)
,则会向Pid
发送无法匹配的退出信号,该信号将无条件退出并退出原因{{ 1}}。
当killed
用作exit/2
而self()
用作Pid
时,我正在使用normal
函数及其行为。
Reason
是不是只有'正常'退出消息被发送到shell进程,所以没有理由退出?
类似地:
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
答案 0 :(得分:3)
看起来Erlang shell(shell.erl)不会处理类型'EXIT'
的{{1}}消息,与其他退出消息的处理方式不同,这意味着它会发送错误并重新启动贝壳。如果您真的想知道这一点,您可以使用debugger以这种方式跟踪程序流程:
normal
shell2.erl
。您需要执行此操作,因为编译器会抱怨shell2
位于粘滞目录中。shell
提示。erl
c(shell2, [debug_info]).
debugger:start().
并选择shell2.erl Module -> Interpret
答案 1 :(得分: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
功能。
对于你的第二种情况(向产生pid
发送消息),回到关于exit
功能的帖子的第一部分,这是合乎逻辑的。您生成的pid
不会捕获退出消息,并忽略(normal) exit
消息。因此shell
只有在您的生成pid
实际退出时才会收到退出消息。它将进入get_command1/5
的第一个条件。由于未调用start_evel
,shell pid
将保持不变。
对于你的第三种情况,我不知道为什么。我还认为is_process_alive(v(8))
应该返回true。
答案 2 :(得分:1)
正如您的第三个示例所示,如果任何进程执行exit(self(), normal)
,那么它会崩溃,而执行exit(AnotherPid, normal)
时不会导致其他进程崩溃。我在R15B上验证了它。我个人认为这是一个错误,因为将退出信号normal
发送到任何进程不应导致其崩溃。
答案 3 :(得分:0)
对于第三种情况,这里的关键点是self()是生成进程的pid而不是shell的pid。
请参阅以下代码:
Eshell V5.9 (abort with ^G)
1&GT;自()。
&LT; 0.32.0&GT;
2 - ; spawn(fun() - &gt; io:format(“这是〜p~n”,[self()]),exit(self(),normal),receive _ - &gt; ok end end)。
这是<0.35.0&gt; &LT; 0.35.0&GT;
3&GT; is_process_alive(V(2))。
假
4&GT;
答案 4 :(得分: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
的用途。