我有一个关于发送信号的c的问题



这是我的代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
#include<unistd.h>
void handler1(int sig) {
    int pid;
    if ((pid = waitpid(-1, NULL, 0)) < 0)
        printf("waitpid error");
    printf("Handler reaped child %dn", pid);
    sleep(1);
}
int main() {
    int i, n;
    if (signal(SIGCHLD, handler1) == SIG_ERR) {
        printf("signal errorn");
    }
    for (i = 0; i < 3; ++i) {
        if (fork() == 0) {
            printf("Hello from child %dn", getpid());
            exit(0);
        }
    }
//    sleep(1);
    printf("Father love you!n");
    while (1);
    exit(0);
}

当我运行它时,它显示以下内容:

Father love you!
Hello from child 7843
Hello from child 7844
Hello from child 7842
Handler reaped child 7842

但我认为应该是

Father love you!
Hello from child 7843
Hello from child 7844
Hello from child 7842
Handler reaped child 7842
Handler reaped child 7843      

有重复的Handler reaped child xx.

如果我取消注释sleep(1);,它将显示我想要的内容:

Hello from child 7858
Handler reaped child 7858
Hello from child 7859
Hello from child 7860
Handler reaped child 7859
Father love you!

我不知道为什么第一个只有一个汉德勒收获的孩子。请帮助我,谢谢你。

操作系统只允许提供一个SIGCHLD信号,告诉您多个子进程已退出。 这意味着您需要在信号处理程序中循环调用waitpid,如下所示:

void sigchld_handler(int unused)
{
    pid_t pid;
    int status;
    for (;;) {
        pid = waitpid(-1, &status, WNOHANG);
        if (pid == -1) {
            if (errno != ECHILD)
                printf("waitpid failure: %sn", strerror(errno);
            return;
        }
        printf("child %d exit status %dn", (int)pid, status);
    }
}

您需要使用 WNOHANG,以便waitpid失败,并将errno设置为在没有更多进程要等待时ECHILD,而不是阻塞(可能永远阻塞(。

此外,为了安全地从信号处理程序内部调用printf,您需要在 main 函数中使用 sigprocmasksigsuspend,以便只有在正常执行被阻止时才能传递信号sigsuspend。 另外,永远不要使用signal,只使用sigaction;signal的规格没有涵盖几个会咬你的重要细节。

int main(void)
{
   sigset_t sigchld_set;
   sigemptyset(&sigchld_set);
   sigaddset(&sigchild_set, SIGCHLD);
   sigset_t unblock_sigchld_set;
   if (sigprocmask(SIG_BLOCK, &sigchld_set, &unblock_sigchld_set)) {
       perror("sigprocmask");
       return 1;
   }
   sigdelset(SIGCHLD, &unblock_sigchld_set);
   struct sigaction sa;
   sigfillset(&sa.sa_mask);
   sa.sa_handler = sigchld_handler;
   sa.sa_flags = SA_RESTART;
   if (sigaction(SIGCHLD, &sa, 0)) {
       perror("sigaction");
       return 1;
   }
   /* fork loop goes here */
   for (;;)
       sigsuspend(&unblock_sigchld_set);
   return 0;
}

在等待所有子进程后main退出将留作练习。 (提示:你需要C11原子类型。

最新更新