【问题标题】:Why does waitpid in a signal handler need to loop?为什么信号处理程序中的 waitpid 需要循环?
【发布时间】:2017-08-22 05:31:06
【问题描述】:

我在一本电子书中读到,waitpid(-1, &status, WNOHANG) 应该放在一个while循环下,这样如果多个子进程同时退出,它们都会被收割。

我通过同时创建和终止 2 个子进程并在不使用循环的情况下通过 waitpid 获取它来尝试这个概念。并且都被收割了。

问题是,是否有必要将 waitpid 置于循环之下?

#include<stdio.h>
#include<sys/wait.h>
#include<signal.h>

int func(int pid)
{
  if(pid < 0)
    return 0;
  func(pid - 1);
}

void sighand(int sig)
{
  int i=45;
  int stat, pid;
  printf("Signal caught\n");
  //while( (
  pid = waitpid(-1, &stat, WNOHANG);
  //) > 0){
  printf("Reaped process %d----%d\n", pid, stat);
  func(pid);
}

int main()
{
  int i;
  signal(SIGCHLD, sighand);
  pid_t child_id;

  if( (child_id=fork()) == 0 )  //child process
  {
    printf("Child  ID %d\n",getpid());
    printf("child exiting ...\n");
  }
  else
  {
    if( (child_id=fork()) == 0 ) //child process
    {
      printf("Child ID %d\n",getpid());
      printf("child exiting ...\n");
    }
   else
    {
      printf("------------Parent with  ID %d \n",getpid());
      printf("parent exiting ....\n");
      sleep(10);
      sleep(10);
    }
  }
}

【问题讨论】:

  • 两个子进程都在被收割。为什么?

标签: c linux unix process


【解决方案1】:

是的。

好的,我会详细说明。

对 waitpid 的每次调用都会收获一个,而且只有一个 child。由于您将调用放在信号处理程序中,因此无法保证第二个孩子在您完成执行第一个信号处理程序之前会退出。对于两个可以的进程(待处理的信号将在您完成时处理),但对于更多,可能是两个孩子将在您仍在处理另一个孩子时完成。由于信号没有排队,您会错过通知。

如果发生这种情况,您将不会收获所有孩子。为了避免这个问题,引入了循环推荐。如果您想看到它发生,请尝试与更多孩子一起进行测试。跑得越多,就越有可能发现问题。

说了这么多,让我们谈谈其他一些问题。

首先,您的信号处理程序调用printf。这是一个主要的禁忌。很少有函数是信号处理程序安全的,printf 绝对不是其中之一。您可以尝试让您的信号处理程序更安全,但更明智的方法是放入一个仅设置一个标志的信号处理程序,然后在您的主程序流程中执行实际的 wait 调用。

由于您的主要流程通常是调用 select/epoll,因此请务必查找 pselectepoll_pwait,并了解它们的作用以及为什么需要它们。

更好(但特定于 Linux),请查找 signalfd。您可能根本不需要信号处理程序。

编辑添加: 该循环不会改变两个信号传递合并到一个处理程序调用中的事实。它所做的是这个调用处理所有待处理的事件。

当然,一旦出现这种情况,您必须使用WNOHANG。导致信号合并的相同工件也可能导致您处理尚未传递信号的事件。

如果发生这种情况,那么一旦您的第一个信号处理程序存在,它将再次被调用。但是,这一次将没有待处理的事件(因为这些事件已被循环提取)。如果不指定WNOHANG,你的wait会阻塞,程序会无限卡住。

【讨论】:

  • 循环waitpid() 如何安全地防止操作系统将两个相同的信号合并为一个?
  • 不会。你只要把它们都收集起来。我会修改答案。
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 2017-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多