无法接收到所有的SIGCHLD

标签 c linux unix operating-system

在下面的代码中,我期望控制台打印十个SIGCHLD catch。我已经通过将 sa_flags 设置为 SA_SIGINFO 并使用 sa_sigaction 而不是 sa_handler 对 SIGCHLD 进行了排队。然而,似乎有些 SIGCHLD 丢失了。为什么?

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

#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);
}

最佳答案

SIGCHLD 是一种标准信号,这意味着多次出现的信号会合并为一个。 Linux 内核维护标准信号的位集,每个信号一位,并支持对一个关联的 siginfo_t 进行排队。

修复:

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);
    }
}

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

而且,迂腐地说,信号处理程序中只能使用有限数量的异步信号安全函数(请参阅 man signal-safety ),printf 不是其中之一。

关于无法接收到所有的SIGCHLD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48750382/

相关文章:

linux - 并排显示两个文件

linux 排序命令结果让我很困惑

c++ - 我可以从 Linux 客户端调用 Windows DLL 吗?

c - Linux/Windows 中的 sleep()/Sleep() 行为

node.js - 如何在 bash 中抑制 npm WARN 弃用消息

unix - AWK 每隔 n 行拆分文件,但将 ID 分组在一起

c - 为什么将数组元素传递给 crypt() 时出现此错误

c - snprintf 给出不同的输出

linux - 为什么编译后.o文件中的函数名与.cc文件中的函数名不同?

c - 选择行为