Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This noncompliant code example relies on the reception of a SIGINT signal to toggle a flag to terminate a loop. However, because interrupted is not declared volatile, the read from it in main() may be optimized away by the compiler despite the assignment to the variable in the signal handler and the loop may never terminate. When compiled on GCC with the -O optimization flag, for example, the program fails to terminate even upon receiving a SIGINT.

Code Block
bgColor#ffcccc
langc
#include <signal.h>

sig_atomic_t interrupted;   /* bug: not declared volatile */

void sigint_handler(int signum) {
  interrupted = 1;   /* assignment may not be visible in main() */
}

int main(void) {
  signal(SIGINT, sigint_handler);
  while (!interrupted) {   /* loop may never terminate */
   /* do something */
  }
  return 0;
}

...

Note, however, that declaring an object volatile is not sufficient to prevent data races when the object is simultaneously accessed from within two or more threads of execution. Additional memory visibility constraints may necessitate the use of platform-specific constructs such as memory barriers, for example, when each of the threads runs on a different processor.

Code Block
bgColor#ffcccc
langc
extern int compute(void*);

static _Bool end_processing;

void* thread_func(void *arg) {
  while (0 == *(volatile _Bool*)&end_processing) {
    int status;
    status = compute(arg);
    if (status) {
      /* notify other threads to end processing */
      end_processing = 1;
      break;
    }
  }
  return 0;
}

...

By adding the volatile qualifier to the variable declaration, interrupted is guaranteed to be accessed from its original address for every iteration of the while loop as well as from within the signal handler.

Code Block
bgColor#ccccff
langc
#include <signal.h>

volatile sig_atomic_t interrupted;

void sigint_handler(int signum) {
  interrupted = 1;
}

int main(void) {
  signal(SIGINT, sigint_handler);
  while (!interrupted) {
   /* do something */
  }
  return 0;
}

...