2011-12-30 106 views
9

我正在處理使用fork()和exec來創建子進程的服務器代碼。當fork()成功並且在CHILD信號被捕獲時被清除,該孩子的PID被註冊。KILL信號是否立即退出進程?

如果服務器需要停止,所有的程序都會被終止,最終會產生一個KILL信號。現在,這是通過遍歷所有已註冊的PID並等待CHILD信號處理程序去除PID來工作的。如果子程序沒有正確退出,這將失敗。因此,我想使用killwaitpid結合使用,以確保PID列表被清除並記錄,否則會執行其他一些操作。

考慮下一個代碼樣品:

kill(pid, SIGKILL); 
waitpid(pid, NULL, WNOHANG); 

摘自waitpid(2)

waitpid函數():成功時返回其狀態已經改變子的進程ID;如果WNOHANG被指定並且存在一個或多個由pid指定的子(ren) ,但尚未更改狀態,則返回0。出錯時,返回-1。

pid給出的過程總是在下一個函數啓動之前消失嗎?在上述情況下,waitpid總是會返回-1

+2

KILL信號相當殘酷,爲什麼不是INT或HUP?還有,「kill」系統調用的返回碼是什麼? 「 – fge 2011-12-30 12:03:21

+0

」等待CHILD信號處理程序...「 - SIGKILL沒有信號處理程序,你知道嗎?除了SIGSTOP和SIGKILL以外,所有的信號都會執行'sigaction'(例如調用處理程序)或缺省值。 SIGSTOP剛剛停止,SIGKILL只是殺死了這個進程。總是。沒有處理或有條件的。 (例外情況是'kill'系統​​調用失敗,因爲你沒有足夠的權限。) – Damon 2011-12-30 12:15:47

+0

@Damon:目標進程不能忽略'SIGKILL',這就對了。但那不是問題/問題。源進程的'kill(2)'系統調用可以在信號在目標進程的上下文中被內核評估之前返回。 'kill(2)'基本上是一個非常簡單的異步通信,必須作爲所有含義來對待。 – 2011-12-30 12:22:07

回答

8

在下一個函數啓動之前,pid給出的過程是否總是消失?

沒有保證。在一個多處理器上,你的進程可能在CPU 0上,而在內核中對於死亡進程的清理髮生在CPU 1上。這是一個經典的競爭條件。即使在單數處理器上也無法保證。

在上述情況下,waitpid總是返回-1嗎?

由於它是一種競爭條件 - 在大多數情況下它可能會。但是沒有保證。


既然你不感興趣的狀態,這semicode可能是你的情況更爲合適:

// kill all childs 
foreach(pid from pidlist) 
    kill(pid, SIGKILL); 

// gather results - remove zombies 
while(not_empty(pidlist)) 
    pid = waitpid(-1, NULL, WNOHANG); 
    if(pid > 0) 
     remove_list_item(pidlist, pid); 
    else if(pid == 0) 
     sleep(1); 
    else 
     break; 
+0

感謝您的解釋,我將無法使用建議的代碼,因爲SIGCHILD處理程序會從pidlist中刪除項目。這讓我可以選擇:檢查進程是否正在運行,如果沒有,請刪除,否則殺死。 – Lekensteyn 2011-12-30 15:28:29

+0

只需刪除'WNOHANG'標誌,您的代碼將按預期工作。 – 2011-12-30 17:12:49

+0

@Lekensteyn:如果已經有一個更新列表的SIGCHLD處理程序,那麼這個處理程序可以調用'waitpid'來移除殭屍進程。那麼'while'循環只需要等待a)所有進程都已經死亡或被埋沒了,或者b)爲了安全起見,一些超時。 – 2011-12-30 18:03:19

4

KILL信號處理程序將在殺死進程CPU時間運行。這可能遠遠晚於您的waitpid呼叫,特別是在加載的系統上,因此waitpid可以很好地返回0.