为什么即使设置了SA_NODEFER标志,sigaction处理程序也不处理每个信号?

我有一个父进程,它生成十个子进程,并使用SIGCHILD处理程序通知子进程何时死亡。 子进程将在它们启动时通知,然后立即退出。
我使用SA_NODEFER标志来防止SIGCHLD信号在太多进入时被丢弃。孩子们都被正确终止并收到了,但是在这个脚本中以及同时通过控制台信号终止两个信号同时发送时间总是显得一体。

#define _POSIX_C_SOURCE 200809L #include  #include  #include  #include  #include  #include  void CHLDHandler(int sig) { char child[] = "Child finished!\n"; write(1, &child, sizeof(child)); } int main(int argc, char const *argv[]) { struct sigaction sa; sa.sa_handler = CHLDHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NODEFER; sigaction(SIGCHLD,&sa,NULL); for (size_t i = 0; i < 10; i++) { int pid = fork(); if (pid == 0) { int pid = getpid(); printf("I'm a child with pid %d!\n", pid); return 0; } } while(1) { wait(NULL); } return 0; } 

基本UNIX信号不排队 – 一次只有一个可以挂起(对于给定的线程)。

如果两个子进程有效地同时终止并因此在“相同”时间提供其SIGCHLD,则您的进程将只有一个待处理的信号。

在收到SIGCHLD后wait 循环是一种长期存在的技术,以补偿SIGCHLD可能“丢失”的事实。 将“Child finished!\ n”通知移动到调用wait的循环,您将获得准确的计数。

UPDATE

如果你必须在你的处理程序中收获,你可以在处理程序中调用wait ,因为它是异步信号安全的 :

 static void CHLDHandler(int sig) { static char child[] = "Child finished!\n"; int save_errno = errno; while (waitpid((pid_t)-1, NULL, WNOHANG) > 0) { write(STDERR_FILENO, &child, sizeof(child) - 1); // don't write the terminating NULL } errno = save_errno; } 

在这种情况下,我不会设置SA_NODEFER,因为另一个SIGCHLD可能会中断(EINTR) waitpidwrite调用。