前面我們看過產生processes及之間的通訊.
那當process發生錯誤時,是怎樣的處理機制呢?
我們先來看一個BIF(內建函數),叫link/1.
簡單範例如下:
-module(e1016a).
-export([sleeper/0]).
sleeper() ->
timer:sleep(30000),
% slepp 30 seconds
exit(resaon_wakeup).
執行過程:
1> c(e1016a).
{ok,e1016a}
2> Pid = spawn(fun e1016a:sleeper/0).
<0.35.0>
3> link(Pid).
true
** exception error: resaon_wakeup
解說:
如上圖所示,erlang shell透過link/1連結sleeper,
當sleeper離開時,會將訊息傳送給erlang shell.
接著我們來看命運的鎖鏈....
-module(e1016b).
-export([fate/1]).
fate(0) ->
receive
_ -> ok
after 5000 ->
exit("Bye! Bang!!")
end;
fate(N) ->
Pid = spawn(fun() -> fate(N-1) end),
link(Pid),
receive
_ -> ok
end.
編譯及執行:
1> c(e1016b).
{ok,e1016b}
2> link(spawn(e1016b, fate, [3])).
true
** exception error: "Bye! Bang!!"
解說:
使用spawn/3來產生, 格式為 spawn(Module, Fun, Args), Args = [terms]
透過遞迴方式,依序產生process,並且link.
整個過程如下:
shell ==link==> fate(3) ==link==> fate(2) ==link==> fate(1) ==link==> fate(0)
shell ==link==> fate(3) ==link==> fate(2) ==link==> fate(1) ==link==> Bye! Bang!!
shell ==link==> fate(3) ==link==> fate(2) ==link==> Bye! Bang!!
shell ==link==> fate(3) ==link==> Bye! Bang!!
shell ==link==> fate(3) Bye! Bang!!
shell ==link==> Bye! Bang!!
shell dead and show reason:Bye! Bang!!
shell 重啟!
透過 link 連接的雙方,當一方exit或dead時,另一方也會受到影響.
這樣子的機制似乎不太理想.
實際上,我們不會這樣子讓一個process把整個系統弄垮.
我們接著來看,要怎樣處理.
捕捉信號的機制.
1> link(spawn(e1016b, fate, [3])).
true
2> receive X -> X end.
{'EXIT',<0.36.0>,"Bye! Bang!!"}
透過上面的過程,可以看到Shell 使用 receive 捕捉到 exit的訊息.
shell依然存活.
可以觀察到格式為tuple, {'EXIT', Pid, Reason}.
這樣我們就可以依據exit的訊息格式,捕捉後做適當處理.