2009-04-30 72 views
22

我有一個長時間的運行過程,我需要它啓動另一個進程(這也將運行很長時間)。我只需要啓動它,然後完全忘記它。如何觸發並忘記子進程?

我設法通過從Programming Ruby書籍中挖出一些代碼來做我所需要的,但我想找到最好/正確的方法,並理解正在發生的事情。下面是我最初:

exec("whatever --take-very-long") if fork.nil? 
Process.detach($$) 


所以,這是這樣的,或者我應該怎麼回事辦呢?

檢查下面我結束了這段代碼,這似乎更有意義的答案後:

(pid = fork) ? Process.detach(pid) : exec("foo") 


我會很感激如何fork作品一些解釋。 [已經得到]

正在分離$$對不對?我不知道爲什麼這會起作用,我真的很想更好地掌握情況。

回答

20

fork函數將您的過程分成兩部分。

這兩個進程然後接收函數的結果。孩子收到的值爲零/ nil(因此知道它是孩子),父母接收孩子的PID。

因此:

exec("something") if fork.nil? 

會使孩子的過程開始「東西」,而父進程將繼續同它在哪裏。

請注意,exec()用當前進程替換,因此子進程永遠不會執行任何後續的Ruby代碼。

Process.detach()的調用看起來可能不正確。我希望它有它的孩子的PID,但如果我正確地讀你的代碼,它實際上是分離父進程。

+1

好吧,我想我得到了.nil?檢查。在孩子中它並不真的返回0,它返回零。所以,如果你在孩子身邊,執行將會運行。 那麼,我將如何捕獲fork的另一個返回值,即返回子進程的id的那個返回值?這樣我就可以直接使用它,而不是依賴$$。 – kch 2009-04-30 10:24:22

+2

只是調用fork並捕獲結果。那麼如果你得到零,做執行,否則你在父母。 – Alnitak 2009-04-30 10:27:07

+0

這是一個非常清晰和簡潔的'fork'定義。很棒的工作,謝謝。 – KomodoDave 2013-01-30 15:09:36

28

Alnitak是對的。下面就來寫一個更明確的方式,無需$$

pid = Process.fork 
if pid.nil? then 
    # In child 
    exec "whatever --take-very-long" 
else 
    # In parent 
    Process.detach(pid) 
end 

分離的目的僅僅是說,要避免zombie processes「當孩子終止我不在乎」。

2

分離$$是不正確的。來自p。 Pickaxe的348(第二版):

$$ Fixnum正在執行的程序的進程號。[R/O]

本節,在「Ruby語言」一章「變量和常量」,是各種紅寶石短$常數解碼很方便 - 但是在線版(第一

所以你實際上在做,從自身分離的程序,而不是從它的孩子什麼。 像其他人說,從孩子分離的正確方法是用孩子的PID從fork()返回。

2

其他的答案是好的如果你確定要分離孩子的過程,但是如果你不介意,或者希望保持附接的子過程(例如,您正在啓動子的服務器/服務的Web應用程序),那麼你可以採取以下簡寫

fork do 
    exec('whatever --option-flag') 
end 

提供了一個塊告訴叉在子進程中執行該塊(只有該塊)的優勢,同時繼續在父母身上。

0

我發現上面的答案打破了我的終端,搞砸了輸出。這是我找到的解決方案。

system("nohup ./test.sh &") 

以防任何人有同樣的問題,我的目標是登陸到SSH服務器,然後保持這一進程無限期地運行。所以test.sh是這樣的

#!/usr/bin/expect -f 
spawn ssh host -l admin -i cloudkey 
expect "pass" 
send "superpass\r" 
sleep 1000000