为何<signal.h>将__sig_atomic_t定义为int而非volatile int?
sig_atomic_t and volatile in Signal Handlers Great question—this is exactly the kind of subtle systems programming detail that catches even seasoned developers off guard. Let’s break this down step by step:
1. What sig_atomic_t actually guarantees
First, let’s clarify the C standard’s intent for sig_atomic_t: it’s a type designed to ensure that single read/write operations on variables of this type are atomic when accessed from a signal handler. That means you won’t get partial values if a signal interrupts a read/write (e.g., no half-updated 64-bit integers on 32-bit systems).
Crucially, the C standard does not require sig_atomic_t to include the volatile qualifier by default. The header definition as plain int is completely compliant—volatile is a separate type qualifier, not part of the type itself.
2. Why your cache/write-back concern is valid
Your worry about write-back vs write-through caching (and compiler optimizations) is spot-on. Without the volatile qualifier, the compiler is free to:
- Cache the variable in a CPU register instead of accessing main memory every time
- Reorder or eliminate reads/writes if it thinks the variable isn’t changing outside the current thread
In this scenario:
- The main thread might update the flag in a register, but not flush it to main memory yet (write-back behavior)
- When a signal triggers, the handler reads the stale value from main memory instead of the updated register value
- This leads to the handler acting on outdated state, which is exactly the bug you’re worried about
3. The correct way to use sig_atomic_t
To fix this, you must explicitly declare your flag with both sig_atomic_t and volatile:
volatile sig_atomic_t signal_flag = 0;
The volatile qualifier tells the compiler:
- Never cache this variable in a register—always read/write directly from main memory
- Don’t optimize away reads/writes, even if it looks like the value isn’t changing in the current execution path
This ensures that changes from the main thread are immediately visible to the signal handler, and vice versa.
4. Why the standard doesn’t include volatile in sig_atomic_t
The C standard leaves volatile as an explicit choice because sig_atomic_t isn’t only for signal handlers. You might use it for atomic operations in a single thread where volatile isn’t necessary. By separating the atomicity guarantee from the volatile requirement, the standard gives programmers flexibility for different use cases.
Wrap-up
Your intuition is correct: using plain sig_atomic_t without volatile can lead to bugs due to compiler optimizations or CPU caching behavior. Always pair sig_atomic_t with volatile when the variable is shared between the main thread and a signal handler—this is the practice that aligns with CSAPP’s guidance, even if the book doesn’t explicitly call out the volatile part in the type definition.
内容的提问来源于stack exchange,提问作者Metal Slime

