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

Time:06-04

I have this code:

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

this program to my understanding should always print cpt = 5 but when i run it on my machine it returns different values (3,4,5) why is that?

CodePudding user response:

The SIGCHLD signal is a little funny and doesn't work like you'd expect: we think we should get one signal per child death, but that's not it.

Instead, it's a kind of level-triggered thing where at some unknown intervals it sends the signal if there are any un-waited-for children.

In the loop you provided that burns through the wait(), this loop is consuming multiple children before the signal handler gets around to it, hence less trips through the handler.

Others have pointed out that you should be using a volatile sig_atomic_t variable, and though this is a good idea, it's not why you're seeing this behavior.

I believe the only way to get a guaranteed one-signal-per-child is to actually wait for the child in the signal handler - this makes it appear more like an edge-triggered signal.

Of course, you're pretty limited to what you can do in the signal handler, so if your application already has a good regimen for waiting for child processes, you likely don't need a SIGCHLD handler.

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

As an alternative, if the while() loop were not so tight and had other processing (or even an explicit delay), there would not be a race condition and you'd see all five SIGCHLD delivered.

  • Related