2015-11-05 113 views
0

在書編程二郎的第13章的結尾:軟件的並行世界,我們都獲得了一段代碼:競爭狀態的例子

keep_alive(Name, Fun) -> 
    register(Name, Pid = spawn(Fun)), 
    on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end). 

而且書上說:

  • 進程Pid可能在執行on_exit之前死亡。
  • 如果兩個程序試圖同時評估keep_alive並且使用相同的值Name,則該代碼具有可能發生的爭用條件

如果兩個程序同時調用keep_alive具有相同Name,那麼register電話之一,因爲名稱已被採取,並且調用進程會死會觸發badarg例外。

所以,它不是過程on_exit之前Pid死亡被稱爲,但過程調用on_exit死亡

什麼用這個作爲一個例子來描述競爭條件,這裏的作者的觀點?

回答

3

不,或者可能實際上死亡。

的過程中提到了Pid可能在Fun第一行中的錯誤,可以嘗試獲得一些外部資源作爲其第一個動作和 失敗(鎖定的文件,一個不存在的數據庫,等等),它可以很快終止非常無循環等

-module(silly). 
-export([do_stuff/0]). 

do_stuff() -> 
    keep_alive(die_bot, fun i_die_fast/0). 

i_die_fast() -> 
    not_ok = io:format("Is this ok?~n"), 
    receive Anything -> 
     ok = io:format("Received: ~tp~n", [Anything]), 
     i_die_fast() 
    end. 

keep_alive(Name, Fun) -> 
    register(Name, Pid = spawn(Fun)), 
    on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end). 

如何將上面的代碼打出來的? (io:format/1始終返回ok,所以它不會匹配not_ok並在第一行中崩潰。)i_die_fast/0似乎永久遞歸,但它永遠不會那麼遠,並且可能會在達到on_exit/2之前死亡。 (但它不是保證死之前on_exit/2被稱爲!歡迎併發。)

關鍵是你不知道。最接近你可以知道的是使用spawn_link,或者在較少耦合的情況下使用spawn,然後使用monitorspawn_monitor

競爭狀態與register是真實的,以及和可能崩潰當前執行的過程 - 所以這是競爭條件。


旁註:

這就是爲什麼我幾乎總是有這樣,如果有衝突,它在孩子,而不是調用的情況下炸燬衍生功能寄存器本身(在大多數情況下,有各種各樣的原因爲什麼你可能想以另一種方式做):

% Note, we don't need the PID of `some_helper` because it is named. 
start() -> 
    _ = spawn_link(fun() -> some_helper() end), 
    main_loop(). 

some_helper() -> 
    true = register(helper, self()), 
    helper_loop().