C 无法接收所有信号

C 无法接收所有信号,c,linux,unix,operating-system,C,Linux,Unix,Operating System,在下面的代码中,我希望控制台打印10个捕获的SIGCHLD。我已经通过将sa_flags设置为sa_sigino并使用sa_sigaction而不是sa_handler将SIGCHLD排队。然而,似乎有些信号丢失了。为什么? 我想fork()可能会被SIGCHLD中断,因此我使用SA_RESTART重新启动fork()。我在不同的计算机上运行同一段代码。在我的MacBook上,它显示[1]24481非法硬件指令。在另一台Linux计算机上,打印少于10个SIGCHLD #include <

在下面的代码中,我希望控制台打印10个捕获的
SIGCHLD
。我已经通过将
sa_flags
设置为
sa_sigino
并使用
sa_sigaction
而不是
sa_handler
将SIGCHLD排队。然而,似乎有些信号丢失了。为什么?

我想
fork()
可能会被
SIGCHLD
中断,因此我使用
SA_RESTART
重新启动
fork()
。我在不同的计算机上运行同一段代码。在我的MacBook上,它显示
[1]24481非法硬件指令
。在另一台Linux计算机上,打印少于10个
SIGCHLD

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

#define CHECK(syscall, msg) do {                    \
    if ((syscall) == -1) {                          \
      perror(msg);                                  \
    }                                               \
  } while(0)

void catch(int signo, siginfo_t *info, void *context) {
  if (signo == SIGCHLD) {
    printf("SIGCHLD caught\n");
  }
}

int main () {
  sigset_t new_set;
  sigemptyset(&new_set);
  sigaddset(&new_set, SIGCHLD);
  struct sigaction act;
  act.sa_sigaction = catch;
  act.sa_mask = new_set;
  act.sa_flags = SA_SIGINFO | SA_RESTART;
  CHECK(sigaction(SIGCHLD, &act, NULL), "sigaction error");

  int pid, i;
  for (i = 0; i < 10; i++) {
    pid = fork();
    if (!pid) return;
  }
  while (1);
}
#包括
#包括
#包括
#包括
#包括
#包括
#定义检查(syscall,msg)do{\
如果((系统调用)=-1){\
佩罗尔(味精)\
}                                               \
}而(0)
无效捕获(int signo、siginfo\u t*info、void*context){
if(signo==SIGCHLD){
printf(“SIGCHLD捕获\n”);
}
}
int main(){
sigset\u t新设置;
SIGEPTYSET(和新设置);
sigaddset(&new_set,SIGCHLD);
结构动作法;
act.sa_sigaction=捕获;
act.sa_mask=新的_集;
act.sa_flags=sa_SIGINFO | sa_重启;
检查(sigaction(SIGCHLD,&act,NULL),“sigaction error”);
int-pid,i;
对于(i=0;i<10;i++){
pid=fork();
如果(!pid)返回;
}
而(1),;
}

SIGCHLD
是一个标准信号,这意味着它的多个事件会合并为一个。Linux内核为标准信号维护一个位集,每个信号一个位,并支持只对一个相关的
siginfo\u t
进行排队

修正:

另外请注意,您不需要显式阻止您处理的信号,因为它会自动为您阻止,除非使用了
SA_NODEFER
标志


而且,迂腐地说,信号处理器中只能使用有限数量的异步信号安全函数(请参阅),
printf
不是其中之一“SA_SIGINFO告诉操作系统将此信号排队。默认情况下,不对传递给进程的信号排队。如果一个信号没有排队,那么在进程或线程运行之前多次设置同一信号只会导致最后一个信号被传递。如果您设置了SA_SIGINFO,信号将排队并全部发送。“它真的会倒塌成一个吗?我尝试了你的代码,但它仍然引发
非法硬件指令
。因为
printf
保证不会在我的代码中同时调用。应该没问题吧?@K.Miao除非
printf
被再次调用
printf
的信号处理程序中断。这可能会导致死锁,因为
printf
锁定流的互斥锁。@K.Miao文档可能不准确。只有实时信号可以排队,而不是标准信号。@K.Miao双重检查:。。。支持仅对一个非rt信号进行排队,以便我们可以获得有关信号原因的更详细信息。
void catch(int signo, siginfo_t*, void*) {
    int status;
    pid_t pid;
    if(signo == SIGCHLD) {
        while((pid = waitpid(-1, &status, WNOHANG)) > 0)
            printf("child %u terminated.\n", (unsigned)pid);
    }
}