R15B03中的Erlang退出/2错误
短拷贝自:R15B03中的Erlang退出/2错误,erlang,erlang-shell,Erlang,Erlang Shell,短拷贝自: exit(Pid,原因)->true 类型: Pid=Pid() 原因=term() 向进程Pid发送带有退出原因的退出信号 如果原因是除normal或kill之外的任何术语,则以下行为适用: 如果Pid未捕获退出,则Pid本身将以退出原因reason退出。如果Pid正在捕获退出,则退出信号将转换为消息{'exit',From,Reason},并传递到Pid的消息队列From是发送退出信号的进程的pid。另请参见过程标志/2 如果Reason是原子normal,Pid将不会退出。如果
exit(Pid,原因)->true
类型:
Pid=Pid()
原因=term()
向进程Pid
发送带有退出原因的退出信号
如果原因是除normal
或kill
之外的任何术语,则以下行为适用:
如果Pid
未捕获退出,则Pid
本身将以退出原因reason
退出。如果Pid
正在捕获退出,则退出信号将转换为消息{'exit',From,Reason}
,并传递到Pid
的消息队列From
是发送退出信号的进程的pid。另请参见过程标志/2
如果Reason
是原子normal
,Pid
将不会退出。如果正在捕获退出,则退出信号将转换为消息{'exit',From,normal}
,并传递到其消息队列
如果Reason
是原子kill
,也就是说,如果调用exit(Pid,kill)
,将向Pid
发送一个不可跟踪的退出信号,该退出信号将无条件退出,退出原因已被杀死
当使用self()
作为Pid
和normal
作为原因时,我正在玩弄exit/2
函数及其行为
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>
Erlang R15B03(erts-5.9.3)[源代码][64位][smp:8:8][异步线程:0][hipe][内核轮询:false]
Eshell V5.9.3(使用^G中止)
1> self()。
2> 退出(self(),正常)。
**异常退出:正常
3> self()。
是否应该只向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
4>生成(fun()->接收Pid->Pid!确定结束)。
5> 出口(v(4),正常)。
真的
6> v(4)!self()。
7> 刷新()。
Shell没事了
好啊
但是:
8>生成(fun()->退出(self(),normal),接收->确定结束)。
9> 进程是否活动(v(8))。
假的
看起来Erlang shell()处理'EXIT'
类型的普通
消息与处理其他退出消息没有任何不同,这意味着它发送错误并重新启动shell。如果您确实想了解这一点,可以使用以下方式跟踪程序流:
下载
将文件名更改为shell2.erl
打开文件并将模块名称更改为shell2
。您需要这样做,因为编译器会抱怨shell
位于粘性目录中
启动erl
提示符
c(shell 2[debug\u info])。
debugger:start()。
模块->解释
并选择shell2.erl
shell 2:start()。
走开李>
看起来Erlang shell()处理'EXIT'
类型的normal
消息与处理其他退出消息没有任何区别,这意味着它发送错误并重新启动shell。如果您确实想了解这一点,可以使用以下方式跟踪程序流:
下载
将文件名更改为shell2.erl
打开文件并将模块名称更改为shell2
。您需要这样做,因为编译器会抱怨shell
位于粘性目录中
启动erl
提示符
c(shell 2[debug\u info])。
debugger:start()。
模块->解释
并选择shell2.erl
shell 2:start()。
走开李>
我认为可以从源代码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) -> <<"* ">>.
get_命令(提示符、Eval、Bs、RT、Ds)->
Parse=fun()->退出(io:Parse_erl_exprs(Prompt))结束,
Pid=生成链接(解析),
获取命令1(Pid、Eval、Bs、RT、Ds)。
获取命令1(Pid、评估、Bs、RT、Ds)->
接收
{'EXIT',Pid,Res}->
{Res,Eval};
{EXIT',Eval,{resash,Stacktrace}}->
报告异常(错误,{Reason,Stacktrace},RT),
获取命令1(Pid,开始评估(Bs,RT,Ds),Bs,RT,Ds);
{'EXIT',Eval,Reason}->
报告异常(错误,{原因,[]},RT),
获取命令1(Pid,开始评估(Bs,RT,Ds),Bs,RT,Ds)
结束。
报告异常(类别、原因、RT)->
报告异常(类别、严重、原因、RT)。
报告异常(类、严重性、{Reason、Stacktrace}、RT)->
标签=严重性标签(严重性),
I=iolist_尺寸(标签)+1,
PF=乐趣(学期,I1)->pp(学期,I1,RT)结束,
SF=fun(M,F,A)->(M=:=erl\u eval)或(M=:=?模块)结束,
io:请求([{put_chars,Tag},
{put_chars,
lib:format_异常(I,Class,Reason,Stacktrace,SF,PF)},
nl])。
开始评估(Bs、RT、Ds)->
Self=Self(),
Eval=spawn_link(fun()->evaluator(Self、Bs、RT、Ds)end),%;
严重性标签(严重)->;
严重性标签(良性)->。
对于第一种情况(向self()发送消息),信号满足第二种情况get_command1/5
,它将首先给出错误消息,并生成一个新的shell pid。请注意start\u eval
功能
对于第二种情况(将消息发送到spawnpid
),返回到关于exit
函数的文章的第一部分,这是合乎逻辑的。生成的pid
不会捕获退出消息,并忽略(正常)退出
消息。因此,只有当您的spawnpid
实际退出时,shell才会收到退出消息。它将进入get_command1/5
的第一个条件。由于未调用start\u evel
,shell pid
将保持不变
对于你的第三个案子,我不知道为什么。我还认为进程是否还活着(
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) -> <<"* ">>.
Eshell V5.9 (abort with ^G)
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