2017-08-22 104 views
0

我讀過一個waitpid(-1,& status,WNOHANG)的電子書,應該放在while循環之下,這樣如果多個子進程同時退出,它們都會被獲得。爲什麼waitpid在信號處理程序中需要循環?

我試着通過在同一時間創建和終止兩個子進程並通過waitpid使用循環來收割它。這些都被收穫了。

問題是,在循環中放置waitpid是非常必要的嗎?

#include<stdio.h> 
#include<sys/wait.h> 
#include<signal.h> 

int func(int pid) 
{ 
    if(pid < 0) 
    return 0; 
    func(pid - 1); 
} 

void sighand(int sig) 
{ 
    int i=45; 
    int stat, pid; 
    printf("Signal caught\n"); 
    //while((
    pid = waitpid(-1, &stat, WNOHANG); 
    //) > 0){ 
    printf("Reaped process %d----%d\n", pid, stat); 
    func(pid); 
} 

int main() 
{ 
    int i; 
    signal(SIGCHLD, sighand); 
    pid_t child_id; 

    if((child_id=fork()) == 0) //child process 
    { 
    printf("Child ID %d\n",getpid()); 
    printf("child exiting ...\n"); 
    } 
    else 
    { 
    if((child_id=fork()) == 0) //child process 
    { 
     printf("Child ID %d\n",getpid()); 
     printf("child exiting ...\n"); 
    } 
    else 
    { 
     printf("------------Parent with ID %d \n",getpid()); 
     printf("parent exiting ....\n"); 
     sleep(10); 
     sleep(10); 
    } 
    } 
} 
+0

兩個子進程正在收割。爲什麼? – rishi

回答

3

是的。

好的,我會詳細說明。

每個waitpid的調用都會收集一個,並且只有一個孩子。由於您將調用放入信號處理程序中,因此不能保證在完成執行第一個信號處理程序之前第二個子程序將退出。對於兩個沒有問題的進程(等待完成時待處理的信號將被處理),但是對於更多的情況,可能會有兩個孩子完成,而您仍然在處理另一個孩子。由於信號沒有排隊,您將錯過通知。

如果發生這種情況,你不會收穫所有的孩子。爲了避免這個問題,引入了循環建議。如果你想看到它發生,試着與更多的孩子一起運行你的測試。你跑得越多,你就越有可能看到問題。

就這樣,讓我們​​來談談其他一些問題。

首先,你的信號處理程序調用printf。這是一個主要的禁忌。很少的功能是信號處理器的安全,並且printf絕對不是一個。你可以嘗試讓你的信號處理器更安全,但更爲明智的做法是放入一個信號處理器,只設置一個標誌,然後在主程序的流程中進行實際的wait調用。

由於您的主要流程通常是調用select/epoll,因此請務必查找pselectepoll_pwait,並瞭解它們的作用以及爲什麼需要它們。

更好(但特定於Linux),查找signalfd。你可能根本不需要信號處理器。

編輯補充: 循環將不會改變兩個信號交付合併成一個處理程序調用的事實。它所做的就是這個呼叫處理所有未決事件。

當然,一旦出現這種情況,您需要必須使用WNOHANG。導致信號合併的相同工件也可能導致您處理信號尚未傳輸的事件。

如果發生這種情況,那麼一旦您的第一個信號處理程序存在,它會再次被調用。但是,這次不會有未決事件(因爲事件已經被循環提取)。如果您未指定WNOHANG,則您的wait塊,程序將無限期地卡住。

+0

如何繞過'waitpid()'安全地讓操作系統將兩個相同的信號合併爲一個? – alk

+0

它不會。你只是收集他們。我會修改答案。 –

相關問題