Linux 表示程序在每次执行时 return 没有相同的值

Linux signals program doesn't return the same value on each execution

我有这个代码:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
int cpt = 0;
void handler (int sig) {
     cpt++ ;
}
int main() {
  int i;
  signal(SIGCHLD, handler);
  for (i = 0; i < 5; i++) {
       if (fork() == 0) {
           exit(0);
       }
   }
   while (wait(NULL) != -1) ;
   printf("cpt = %d\n", cpt);
   return 0;
}

根据我的理解,这个程序应该总是打印 cpt = 5 但是当我 运行 它在我的机器上时它 returns 不同的值 (3,4,5) 这是为什么?

SIGCHLD 信号有点滑稽,并不像您预期​​的那样工作:我们认为 我们应该每个 child 得到一个信号死亡,但事实并非如此。

相反,它是一种 level-triggered 东西,如果有 any un-waited-for child,它会以未知的间隔发送信号任.

在您提供的贯穿 wait() 的循环中,此循环在信号处理程序绕过它之前消耗了多个 children,因此通过处理程序的次数较少。

其他人指出您应该使用 volatile sig_atomic_t 变量,虽然这是个好主意,但这并不是您看到此行为的原因。

我相信获得保证 one-signal-per-child 的唯一方法是实际等待信号处理程序中的 child - 这使它看起来更像一个 edge-triggered 信号。

当然,您在信号处理程序中可以做的事情非常有限,所以如果您的应用程序已经有一个很好的等待 child 进程的方案,您可能不需要 SIGCHLD处理程序。

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

static volatile sig_atomic_t cpt = 0;

static void handler(int sig) {
     cpt++;
     wait(NULL);  // ADD ME
}

int main() {
  int i;
  signal(SIGCHLD, handler);
  for (i = 0; i < 5; i++) {
       if (fork() == 0) {
           exit(0);
       }
   }
   while (wait(NULL) != -1) ;
   printf("cpt=%d\n", cpt);
   return 0;
}

作为替代方案,如果 while() 循环不是那么紧密并且有其他处理(甚至是显式延迟),则不会出现竞争条件,您会看到所有五个 SIGCHLD 交付。