2017-08-22 69 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

它不会。你只是收集他们。我会修改答案。 –

相关问题