第9章 并發程式設計中的錯誤處理
1. 連結:連結定義了一種在兩個程序之間的傳播路徑。如果兩個程序被連結在一起,如果其中一個程序消亡,那麼系統就會向另一個程序發送一個退出信号。我們把一群與某個給定的程序進行外國投資的程序集合稱為該程序的連結集。
連結通過在一個程序中調用link(Pid)來完成,Pid是另一個程序的ID。
2. 退出信号:當一個程序消亡時,它會産生一個叫做退出信号的東西。系統會向這個程序的所有連結程序發送這個退出信号。
退出信号不是一個消息,它是一個信号。退出信号包含一個參數來描述程序消亡的原因,可以通過調用exit(Reason),也可以與系統自動設定。
當一個程序成功的完成spawn所指定的函數而退出時,Why就是normal。
3. 系統程序:當一個程序接收到一個非正常的退出信号時它自己也會消亡,除非它是那種特殊類型的程序-系統程序。當Pid程序向一個系統程序發送一個内容Why的退出信号時,系統會把退出信号轉換為消息{'EXIT', Pid, Why},然後送入到系統程序郵箱。
可以通過在一個程序中調用process_flag(trap_exit, true)來将這個程序轉換為一個系統程序。
4. 裝死:在程序Pid1中調用exit(Pid2,X),這時Pid1會向Pid2發送一個退出信号,但Pid1并沒有退出。
5. 程序收到退出信号後的處理關系:
是否捕獲 收到的退出信号 收到信号後的動作
是否是系統程序)
true kill 消亡,向連結集廣播退出信号killed
true X 将{'EXIT', Pid, X}消息加入到郵箱
false normal 繼續運作,不做任何事
false kill 消亡,向連結集廣播退出信号killed
false X 消亡,向連結集廣播退出信号X
6. kill退出信号可以殺死任何程序,而不是向它發送消息。
exit(Pid, kill)會向程序Pid發送kill退出信号
而exit(kill)隻會向連結程序發送原因為kill的退出消息,而不是kill退出信号。
7. on_exit處理程式
on_exit(Pid, Fun) ->
spawn(fun() ->
process_flag(trap_exit, true),
link(Pid),
receive
{'EXIT',Pid,Why} -> Fun(Why)
end
end).
8. 捕獲退出的程式設計模式
模式一:我不在乎建立的程序是否崩潰
建立一個并行程序,當被生成的程序崩潰時,目前程序不會察覺
Pid = spawn(Fun).
模式二:如果我建立的程序非正常的崩潰,我也消亡
%%不要在這之前設定退出信号捕獲狀态
Pid = spawn_link(Fun).
模式三:如果我建立的程序崩潰,我需要處理錯誤
...
process_flag(trap_exit, true),
Pid = spawn_link(Fun),
...
loop(...).
loop(State) ->
receive
{'EXIT', SomePid, Reason} ->
%% do somethin with the error
loop(State);
...
end
9. erlang:is_process_alive(Pid) -> true|false,檢視程序Pid是否還活着。
10. 錯誤處理原語
@spec spawn_link(Fun) -> Pid %% 建立程序并連結它們
@spec process_flag(trap_exit, true) %% 把一個普通程序轉換為系統程序,可以再把标志設為false而取消對退出信号的處理
@spec link(Pid) -> true %% link是對稱的。如果Pid不在在,會抛出noproc異常,如果已經連結,系統會忽略這個調用(不會傳回false)
@spec unlink(Pid) -> true %% 移除先前的link
@spec exit(Why) -> none() %% 如果不在catch之内的話,會向目前程序的連結集廣播退出信号
@spec exit(Pid, Why) -> true
@spec erlang:monitor(process, Item) -> MonitorRef %% 建立一個螢幕,其中Item是一個Pid或者是一個注冊的原子
螢幕是非對稱的,A監視B時,B退出時,A會收到退出信号,而A退出時,B不會收到退出信号。
11. 存活程序:消亡後會被自動重新開機
keep_alive(Name, Fun) ->
register(Name, Pid=spawn(Fun)),
on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).
這個代碼中存在競争性條件,有問題。