【问题标题】:Why does a sigaction handler not handle every signal even if the SA_NODEFER flag is set?为什么即使设置了 SA_NODEFER 标志,sigaction 处理程序也不处理每个信号?
【发布时间】:2018-05-11 14:03:31
【问题描述】:

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

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

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

【问题讨论】:

  • 这是适当的,如果不是完全重复的话:stackoverflow.com/questions/8398298/handling-multiple-sigchld
  • 我明白了。我的任务表明它应该是一个信号处理程序,显然 signalfd 的手册页说它是信号处理程序的替代品。因此,虽然另一种方式可行,但它似乎也可以使用信号处理程序。

标签: c signals


【解决方案1】:

基本的 UNIX 信号不排队 - 一次只能有一个(对于给定线程)待处理。

如果两个子进程在同一时间有效终止并因此在“同一”时间传递它们的 SIGCHLD,则您的进程将只有一个信号待处理。

waiting 在收到 SIGCHLD 后循环 是一种长期建立的技术,用于补偿 SIGCHLD 可能“丢失”的事实。将“孩子完成!\n”通知移动到调用wait 的循环中,您将获得准确的计数。

更新

如果你必须在你的处理程序中收获,你可以在处理程序中调用wait,因为它是async-signal-safe

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 调用。

【讨论】:

  • 谢谢您的回答。我试过那个方法,效果很好!我的任务明确指出要使用处理程序解决此问题。说不能正确宣布终止子进程是否正确,因为我的进程管理器只从它们发送了这么多信号?
  • @NiklasN.,我对这个答案的更新中的 sig 处理程序怎么样?
  • 不会为第一个调用处理程序然后留在其中吗?我正在寻找一种在每次有信号进入时调用处理程序的方法,但似乎没有解决“信号被丢弃”问题的方法,除了用某种形式的 wait() 收集孩子并忽略处理程序.
  • 您的解决方案只需稍作改动即可工作。 waitpid() 返回 0,如果 WNOHANG 是它返回的原因。所以编辑 while 语句应该让代码正常工作。不过,系统之间可能会有所不同。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多