2013-01-25 97 views
3

如果給定兩個鏈接進程childparent,進程child如何檢測到parent正常退出(終止)?進程正常退出

作爲一名絕對的Erlang初學者,我認爲一個過程在沒有其他事情的情況下使用exit(normal)退出。然後,這標誌着所有鏈接的過程,其中

  • 的具有trap_exit設置爲false過程的行爲是忽略該信號,並
  • 的具有進程的行爲trap_exit集到true是生成消息{'EXIT', pid, normal}其中pid是終止進程的進程標識。

我認爲這是Learn You Some Erlang for Great GoodErlang documentation其中說明以下內容的理由。

如果退出原因是原子正常,則稱進程正常終止。沒有更多代碼執行的進程正常終止。

顯然是錯誤的(?),因爲exit(normal)顯示命令提示符** exception exit: normal,使下面工作的代碼。正在退出,因爲沒有更多的代碼要執行不會生成異常,並且不會使我的代碼正常工作。

作爲示例,請考慮以下代碼。

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

start() -> 
    io:format("Parent (~p): started!\n",[self()]), 
    P = spawn_link(?MODULE,test,[]), 
    io:format(
     "Parent (~p): child ~p spawned. Waiting for 5 seconds\n",[self(),P]), 
    timer:sleep(5000), 
    io:format("Parent (~p): dies out of boredom\n",[self()]), 
    ok. 

test() -> 
    io:format("Child (~p): I'm... alive!\n",[self()]), 
    process_flag(trap_exit, true), 
    loop(). 

loop() -> 
    receive 
      Q = {'EXIT',_,_} -> 
       io:format("Child process died together with parent (~p)\n",[Q]); 
      Q -> 
       io:format("Something else happened... (~p)\n",[Q]) 
    after 
      2000 -> io:format("Child (~p): still alive...\n", [self()]), loop() 
    end. 

這產生如下輸出。

([email protected])> test:start(). 
Parent (<0.145.0>): started! 
Parent (<0.145.0>): child <0.176.0> spawned. Waiting for 5 seconds 
Child (<0.176.0>): I'm... alive! 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Parent (<0.145.0>): dies out of boredom 
ok 
([email protected])10> Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
Child (<0.176.0>): still alive... 
exit(pid(0,176,0),something). 
Child process died together with parent ({'EXIT',<0.194.0>,something}) 

如果必須手動執行exit(pid(0,176,0),something)命令以防止孩子永遠活着。 在start更改ok.exit(normal)使執行這樣下去

([email protected])3> test:start(). 
Parent (<0.88.0>): started! 
Parent (<0.88.0>): child <0.114.0> spawned. Waiting for 5 seconds 
Child (<0.114.0>): I'm... alive! 
Child (<0.114.0>): still alive... 
Child (<0.114.0>): still alive... 
Parent (<0.88.0>): dies out of boredom 
Child process died together with parent ({'EXIT',<0.88.0>,normal}) 
** exception exit: normal 

我的具體問題有以下幾種。

  1. 如何使上述代碼按預期工作。也就是說,如何在不更改父進程的情況下確保子進程與父進程一起死亡?
  2. 爲什麼exit(normal)在CLI中生成** exception exit: normal?我很難將異常看作是正常的事情。 Erlang文檔中的情節是什麼意思?

我認爲這些必須是非常基本的問題,但我似乎無法弄清楚這一點.... 我在Windows(x64)上使用Erlang 5.9.3.1。

回答

4

Erlang shell擁有用於將命令評估爲單獨進程的工作器,並且您鍵入的所有命令都由相同進程運行。當你的start函數完成時,worker仍然活着,當你用exit()殺死它時,shell會理解爲工作者異常(因爲worker在正常情況下永遠不會死掉)。

所以:

  1. 您應該運行由spawnspawn_link
  2. CLI開始作爲獨立的進程記錄所有的工人退出作爲例外,正常過

附:對不起,我的英語

P.P.S. spawn(fun() -> test:start() end).按預期工作

4> spawn(fun() -> test:start() end). 
Parent (<0.41.0>): started! 
<0.41.0> 
Parent (<0.41.0>): child <0.42.0> spawned. Waiting for 5 seconds 
Child (<0.42.0>): I'm... alive! 
Child (<0.42.0>): still alive... 
Child (<0.42.0>): still alive... 
Parent (<0.41.0>): dies out of boredom 
Child process died together with parent ({'EXIT',<0.41.0>,normal}) 
+0

我明白了。感謝您的明確解釋。建議的解決方案有效。我真的不明白爲什麼shell會以這種方式工作,但這只是我想的方式;)。 – Semafoor

+0

這是erlang的方式;) –

2

對@PetrKozorezov的問題發表評論。外殼沒有任何特別的表現。 shell工作進程只是一個正常的進程,所以如果任何進程連接它崩潰,那麼它也會崩潰。然後將開始另一個工作進程。這是正常的Erlang的方式

start/0功能只是返回並做終止其進程,它只是輸出「垂死無聊」的消息。這就是爲什麼循環繼續進行,它沒有得到一個exit信號,因爲沒有進程已經死亡。

當您更改start/0函數結束與exit(normal)然後你做終止shell進程如此的exit信號被髮送到循環過程,從而獲取{'EXIT',...,...}消息和死亡。

當@PetrKozorezov在一個單獨的過程,然後執行它start/0發送的出口normal信號,其導致其死亡的循環處理後死亡催生您的原始start/0功能。

這是非常正常的Erlang行爲和風格。您通常會而不是結束a 開始函數與exit但留給呼叫者決定何時死亡。

還有一個小點:由於起始功能的作用是spawn_link,您通常會將其稱爲start_link。假設start函數只是spawn的一個過程。當然,這只是一個慣例,但常見,所以你沒有犯錯。