Here is a simple toy that uses volatile sig_atomic_t .
#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #define UNUSED(x) (void) (x) volatile sig_atomic_t quit; void sigusr1_handler(int sig) { UNUSED(sig); write(1, "handler\n", 8); quit = 1; } int main() { struct sigaction sa; sa.sa_handler = sigusr1_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (sigaction(SIGUSR1, &sa, NULL) == -1) { perror("sigaction"); return 1; } quit = 0; while (!quit) ; printf("Exiting ...\n"); return 0; }
I think I know why volatile sig_atomic_t needed for the quit variable in this particular program.
- Without
volatile compiler can optimize while (!quit) ; to an endless cycle. It does not find a loop modifying quit , so it assumes that quit always remains 0 . - Updating in
quit or reading quit should occur in one machine instruction. If several machine instructions are required to update or read quit , then if a signal handler is called during the update, reading in the signal handler may see an inconsistent value in quit .
Still correcting? If not, please correct me in your answer.
Now I want to study a general rule when sig_atomic_t necessary in the context of signal processing. Jonathan Leffler explained in a comment that it is not easy to provide generalization.
Can you provide a list of known scenarios where the variable should be defined as sig_atomic_t from the standard C point? This should not be an exhaustive list. It could be a list that a less experienced developer might turn to when writing C software with signal processing code.
c signals
Lone learningner
source share