在处理SIGCHLD之前,wait()函数是否返回?

时间:2018-12-11 00:19:55

标签: c signals

所以我有一个针对SIGCHLD的自定义处理程序和一个wait()函数。在父级向其发送信号SIGUSER2后,该子级将退出。在此示例中,当子级调用“ exit(0)”时,父级将处理SIGCHLD并退出,还是“ wait()”函数可能在处理SIGCHLD信号之前返回?

#include<stdio.h> 
#include<wait.h> 
#include<signal.h> 
pid_t pid; 
int counter = 0; 
void handler1(int sig) 
{ 
    printf("A\n");
    kill(pid, SIGUSER2);
} 
void handler2(int sig) 
{ 
    printf("B\n");
    exit(0); 
} 

int main() 
{ 
    signal(SIGUSR1, handler1);
    signal(SIGCHLD, handler2); 
    if ((pid = fork()) == 0) 
    { 
        signal(SIGUSR1, handler2);
        kill(getppid(), SIGUSR1); 
        while(1) ; 
    } 
    if ((p = wait(&status)) > 0) 
    { 
        printf("wait returned before SIGCHLD");
    } 
} 

1 个答案:

答案 0 :(得分:1)

wait的联机帮助页中,它可以获取EINTR

  

未设置EINTR WNOHANG并捕获到畅通的信号或SIGCHLD

因此,如果SIGCHLD有一个处理程序,而您在wait中,则信号将首先发生

这才有意义。因为SIGCHLD处理程序是执行wait来收割孩子的自由。某些程序在基线代码中不执行wait,但依赖处理程序。

正如其他人所提到的,不要在处理程序中执行printf [它执行malloc并且所有赌注都关闭了]。但是,执行wait是可以的[在处理程序中可以进行某些系统调用。

您的程序有几个问题。我重构了一下。它显示SIGCHLDwait完成之前(如手册页所示)。

请注意,这是一项相当不错的测试,但是确定的测试可能涉及到一个第三过程,该过程必须杀死原始孩子(小睡后 )以允许家长输入wait

也就是说,在主流程进入kill之后,wait将会发生(在流程3中)。

我没有这样做,所以这是更简单的版本:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>

pid_t pid;
volatile int gotsig = 0;

void
handler_cld(int sig)
{
    gotsig = 1;
}

void
handler_usr1(int sig)
{
    exit(0);
}

int
main()
{
    int status;

    signal(SIGUSR1, handler_usr1);
    signal(SIGCHLD, handler_cld);

    pid = fork();
    if (pid == 0) {
        while (1);
    }

    // kill the child
    kill(pid,SIGUSR1);

    if ((pid = wait(&status)) > 0) {
        printf("wait returned %s SIGCHLD\n",gotsig ? "after" : "before");
    }

    return 0;
}

更新:

这是更复杂的版本,它使用单独的“杀手”过程来杀死孩子,但结果是相同的:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>

volatile int gotsig = 0;

void
handler_cld(int sig)
{
    gotsig += 1;
}

void
handler_usr1(int sig)
{
    exit(0);
}

int
main()
{
    int status;

    signal(SIGUSR1, handler_usr1);
    signal(SIGCHLD, handler_cld);

    pid_t pidcld = fork();
    if (pidcld == 0) {
        while (1);
    }

    pid_t pidkill = fork();
    if (pidkill == 0) {
        sleep(1);
        // kill the child
        kill(pidcld,SIGUSR1);
        sleep(3);
        exit(0);
    }

    pid_t pidany;

    // wait for child
    if ((pidany = waitpid(pidcld,&status,0)) > 0) {
        printf("wait on child returned %s SIGCHLD\n",
            gotsig ? "after" : "before");
    }

    // wait for child
    if ((pidany = waitpid(pidkill,&status,0)) > 0) {
        printf("wait on killer returned %s SIGCHLD\n",
            gotsig ? "after" : "before");
    }

    return 0;
}