[每日一Errr~lang] process die & error handling
2010-03-02 09:03:04| 分类:
lang_erlang
| 标签:
|举报
|字号大中小 订阅
各位观众早上好,欢迎收看《每日一Errr~lang》节目。近日KKTV在装修新的办公楼,加上工作人员欢度元宵佳节,工作难免懈怠,两日没有制作节目了。在此深表歉意。
上一期我们介绍了 erlang process 的诞生与发展,本期我们将重点讨论 erlang process 死亡的过程。
erlang process 最大的好处,就是当一个 process 死亡时,可以给另一个 process 发送 exit signal。
只要通过 link(Pid),可将"调用 link(Pid) 的 process"和 Pid 两者连接起来,无论谁死亡,都会给另一方发 signal。
下面来看看在各种 exit 情况下,process 的行为。
normal exit (normal termination)
一个 process 正常执行完自己的逻辑而退出,称为 normal exit。如果 bar 不是 trap exit,则 normal exit 情况下不会给 bar 发 exit signal。
-------------------------------------------------
-module(normaldie).
-export([foo/0, bar/1]).
foo() ->
receive
after timer:seconds(10) -> true
end,
io:format("foo exit~n").
bar(Pid) ->
link(Pid),
receive
Any ->
io:format("recv ~p~n", [Any])
end.
-------------------------------------------------
1> c(normaldie).
{ok,normaldie}
2> Pid1 = spawn(fun normaldie:foo/0).
<0.38.0>
3> Pid2 = spawn(normaldie, bar, [Pid1]).
<0.40.0>
foo exit
4> is_process_alive(Pid1).
false
5> is_process_alive(Pid2).
true
-------------------------------------------------
如果 bar 设置了 trap exit 则 foo 退出时,会给 bar 发送 exit signal。即使是 normal exit 也会发。
格式:{'EXIT', Pid, Why}, Pid 是死亡的 process id, Why 就是为啥死亡了。
-------------------------------------------------
-module(trapdie).
-export([foo/0, bar/1]).
foo() ->
receive
after timer:seconds(10) -> true
end,
io:format("foo exit~n").
bar(Pid) ->
process_flag(trap_exit, true),
link(Pid),
loopbar(Pid).
loopbar(Pid) ->
receive
{'EXIT', Pid, Why} ->
io:format("~p died with: ~p~n", [Pid, Why])
end,
loopbar(Pid).
-------------------------------------------------
1> c(trapdie).
{ok,trapdie}
2> Pid1 = spawn(fun trapdie:foo/0).
<0.38.0>
3> Pid2 = spawn(trapdie, bar, [Pid1]).
<0.40.0>
foo exit
<0.38.0> died with: normal
4> is_process_alive(Pid1).
false
5> is_process_alive(Pid2).
true
-------------------------------------------------
non-normal exit
异常退出,如果 bar 没有 trap exit,则 bar 不会收到 exit signal,且会被强制退出。
-------------------------------------------------
-module(nonnormal).
-export([foo/0, bar/1]).
foo() ->
Val = receive
{divide, N} ->
1/N
end,
io:format("foo exit = ~p~n", [Val]).
bar(Pid) ->
% process_flag(trap_exit, true),
link(Pid),
loopbar(Pid).
loopbar(Pid) ->
receive
{'EXIT', Pid, Why} ->
io:format("~p died with: ~p~n", [Pid, Why])
end,
loopbar(Pid).
-------------------------------------------------
1> c(nonnormal).
{ok,nonnormal}
2> Pid1 = spawn(fun nonnormal:foo/0).
<0.38.0>
3> Pid2 = spawn(nonnormal, bar, [Pid1]).
<0.40.0>
4> Pid1 ! {divide, 0}.
{divide,0}
=ERROR REPORT==== 2-Mar-2010::08:28:56 ===
Error in process <0.38.0> with exit value: {badarith,[{nonnormal,foo,0}]}
5> is_process_alive(Pid1).
false
6> is_process_alive(Pid2).
false
-------------------------------------------------
如果打开 bar 的 trap exit,则结果是这样:
-------------------------------------------------
1> c(nonnormal).
{ok,nonnormal}
2> Pid1 = spawn(fun nonnormal:foo/0).
<0.38.0>
3> Pid2 = spawn(nonnormal, bar, [Pid1]).
<0.40.0>
4> Pid1 ! {divide, 0}.
=ERROR REPORT==== 2-Mar-2010::08:31:01 ===
Error in process <0.38.0> with exit value: {badarith,[{nonnormal,foo,0}]}
<0.38.0> died with: {badarith,[{nonnormal,foo,0}]}
{divide,0}
5> is_process_alive(Pid1).
false
6> is_process_alive(Pid2).
true
-------------------------------------------------
我们还可以通过调用 exit(Why) 直接退出 process。
-------------------------------------------------
-module(forceexit).
-export([foo/0, bar/1]).
foo() ->
receive
after timer:seconds(15) -> true
end,
io:format("foo exit~n"),
exit({badarith,[{nonnormal,foo,0}]}).
bar(Pid) ->
process_flag(trap_exit, true),
link(Pid),
loopbar(Pid).
loopbar(Pid) ->
receive
{'EXIT', Pid, Why} ->
io:format("~p died with: ~p~n", [Pid, Why])
end,
loopbar(Pid).
-------------------------------------------------
1> c(forceexit).
{ok,forceexit}
2> Pid1 = spawn(fun forceexit:foo/0).
<0.38.0>
3> Pid2 = spawn(forceexit, bar, [Pid1]).
<0.40.0>
foo exit
<0.38.0> died with: {badarith,[{nonnormal,foo,0}]}
4> is_process_alive(Pid1).
false
5> is_process_alive(Pid2).
true
-------------------------------------------------
kill exit
这又可分两种情况讨论,情况一:
<1> foo 被 kill
<2> bar 没有开启 trap exit
<3> foo, bar 都挂了,则 barbar 收到 killed
-------------------------------------------------
-module(killdie).
-export([foo/0, bar/1, barbar/1]).
foo() ->
receive
after timer:seconds(20) -> true
end,
io:format("foo exit~n"),
exit(kill).
bar(Pid) ->
% process_flag(trap_exit, true),
link(Pid),
loopbar(Pid).
barbar(Pid) ->
process_flag(trap_exit, true),
link(Pid),
loopbar(Pid).
loopbar(Pid) ->
receive
{'EXIT', Pid, Why} ->
io:format("I'm ~p, ~p died with: ~p~n", [self(), Pid, Why])
end,
loopbar(Pid).
-------------------------------------------------
1> c(killdie).
{ok,killdie}
2> Pid1 = spawn(fun killdie:foo/0).
<0.38.0>
3> Pid2 = spawn(killdie, bar, [Pid1]).
<0.40.0>
4> Pid3 = spawn(killdie, barbar, [Pid2]).
<0.42.0>
foo exit
I'm <0.42.0>, <0.40.0> died with: killed
-------------------------------------------------
情况二:
<1> foo 被 kill
<2> bar 开启 trap exit
<3> foo 挂了,bar 收到 kill
-------------------------------------------------
1> c(killdie).
{ok,killdie}
2> Pid1 = spawn(fun killdie:foo/0).
<0.38.0>
3> Pid2 = spawn(killdie, bar, [Pid1]).
<0.40.0>
4> Pid3 = spawn(killdie, barbar, [Pid2]).
<0.42.0>
foo exit
I'm <0.40.0>, <0.38.0> died with: kill
-------------------------------------------------
情况一、二的区别,就在于 {'EXIT', Pid, Why} 中的 Why 是 kill 还是 killed。很细微的差别,具体用于啥地方呢?主持人我也还没研究出来,呵呵。
本期节目到此结束,不知道各位观众看懂了么~
评论这张
转发至微博
转发至微博
评论