2017-04-09 53 views
0

簡單代碼:運行報表給出不同的輸出

-module(on_exit). 
-export([on_exit/2, test/0]). 

on_exit(Pid, Fun) -> 
    spawn(fun() -> 
        Ref = erlang:monitor(process, Pid), 
        receive 
         {'DOWN', Ref, process, Pid, Why} -> 
          Fun(Why) 
        end 
      end). 

test() -> 
    Fun1 = fun() -> receive Msg -> list_to_atom(Msg) end end, 
    Pid1 = spawn(Fun1), 

    Fun2 = fun(Why) -> io:format("~w died with error: ~w~n", [Pid1, Why]) end, 
    _Pid2 = spawn(on_exit, on_exit, [Pid1, Fun2]), 

    Pid1 ! hello. 

在shell:

1> c(on_exit). 
{ok,on_exit} 

2> on_exit:test(). 
<0.39.0> died with error: noproc 
hello 

3> 
=ERROR REPORT==== 9-Apr-2017::05:16:54 === 
Error in process <0.39.0> with exit value: {badarg,[{erlang,list_to_atom,[hello],[]},{on_exit,'-test/0-fun-0-',0,[{file,"on_exit.erl"},{line,14}]}]} 

預期輸出:

5> Pid1 ! hello. 
<0.35.0> died with error: {badarg,[{erlang,list_to_atom,[hello],[]}]} 
hello 

6> 
=ERROR REPORT==== 9-Apr-2017::05:15:47 === 
Error in process <0.35.0> with exit value: {badarg,[{erlang,list_to_atom,[hello],[]}]} 

事實上,預期輸出是我看看我是否將test()中的每行都粘貼到了shell中。爲什麼我在函數內運行相同的行時會出現noproc(無進程)錯誤?

docs

12.8監視器

的替代方法鏈路監視器。進程Pid1可以通過調用BIF erlang:monitor(process,Pid2)爲Pid2創建一個 監視器。 函數返回一個引用Ref。

如果PID2與退出原因原因終止,一個「向下」消息被髮送 到PID1:

{'DOWN', Ref, process, Pid2, Reason} 

如果PID2不存在時,「向下」消息被立即用 原因集發送到noproc

+0

如果您在Pid1之前添加'timer:sleep(100)',您會得到預期的輸出! hello.'? – Dogbert

+0

@Dogbert,是的!這似乎表明'spawn()'異步執行。 – 7stud

回答

1

你的代碼包含一個競爭條件 - spawn是異步過程之前可能會返回被催生,你可能最終發送和崩潰Pid1on_exit:on_exit/2前開始監控它,這將導致erlang:monitor/2呼籲立即發送noproc消息給來電者:

1> Pid = spawn(fun() -> ok end). 
<0.59.0> 
2> erlang:monitor(process, Pid). 
#Ref<0.0.1.106> 
3> flush(). 
Shell got {'DOWN',#Ref<0.0.1.106>,process,<0.59.0>,noproc} 
ok 

代碼工作在外殼精可能是因爲二郎VM在shell當代碼被編譯比慢慢地執行一些事情,但這種行爲是不能保證。這是一個經典的競賽條件。

Erlang爲此提供了一個解決方案:erlang:spawn_monitor/{1,3}。保證該功能在產生功能後立即連接顯示器。您將不得不重新安排您的代碼來使用它,而不是spawn/3 + erlang:monitor/1

+0

謝謝。我沒有打擾檢查'monitor/2'的定義,因爲我正在閱讀有關進程的erlang文檔 - 並沒有提到它是異步的,這是一個重要的細節。但是,現在我檢查了定義:*注意! 監視器請求是一個異步信號。也就是說,信號到達目的地需要時間。* Wtf ?!事件回調循環哪裏可以添加執行monitor/2的樂趣? – 7stud