C++11及以后并发编程中volatile的作用及必要性探讨
Great question—this is one of the most persistent misconceptions in C++ concurrency, so it’s totally fair to be confused, especially since you didn’t find it covered in C++ Concurrency in Action (that book sticks strictly to standard, portable concurrency, which says a lot!). Let’s break this down clearly:
First: Volatile Is Not Designed for Concurrency
Let’s get this straight: The C++ standard defines volatile to handle memory that can change outside the compiler’s control, not multi-threaded access. Its only core jobs are:
- Preventing the compiler from optimizing away reads/writes to variables (e.g., memory-mapped hardware registers, where reading/writing directly interacts with hardware and can’t be cached in registers).
- Ensuring variables modified in signal handlers are visible to the main thread (since signals are asynchronous events the compiler can’t predict).
Crucially, volatile does not guarantee any of the things you need for safe multi-threading:
- It doesn’t prevent CPU instruction reordering (a major issue for inter-thread visibility).
- It doesn’t provide atomicity (a
volatile int’s increment is still a read-modify-write operation that can be interrupted by another thread). - It doesn’t enforce the memory fence semantics needed to sync changes across CPU cores.
So: Can You Stick to Atomic, Mutex, Etc.?
Absolutely. In standard, portable C++ concurrency, you never need volatile. The standard library’s tools are specifically built to handle all concurrency requirements:
std::atomicgives you atomic operations and fine-grained control over memory visibility via memory orders (e.g.,memory_order_acquire,memory_order_release).std::mutexandstd::lock_guardcreate critical sections that ensure exclusive access, and guarantee changes made inside are visible to other threads once the mutex is unlocked.std::condition_variablehandles thread wake-up and synchronization without any need forvolatile.
Using these components ensures your code follows the C++ memory model, making it safe and portable across compilers and platforms.
Are There Any Concurrency Scenarios Where Volatile Is Required?
Almost never—unless you’re dealing with non-standard, platform-specific edge cases:
- Legacy compiler extensions: Some older compilers (like early versions of MSVC) added non-standard semantics to
volatilethat made it behave somewhat likestd::atomicfor multi-threading. But this is not standard C++, and relying on it will break your code on other compilers. - Embedded systems with limited standard library support: If your target platform has poor or no support for
std::atomic, you might need to usevolatilealongside platform-specific memory barriers to simulate atomic behavior. But this is a last resort, not a standard practice. - Signal-handler ↔ thread interaction: If you have a variable shared between a signal handler and a thread (not two threads), you’ll need
volatileto ensure the main thread sees changes from the signal handler. But this is an asynchronous IPC scenario, not typical multi-threaded concurrency.
Wrapping Up
For 99% of standard C++ concurrency use cases, forget about volatile. Stick to std::atomic, mutexes, and other standard library components—they’re designed explicitly for the job, and they’ll keep your code safe, portable, and easy to maintain.
内容的提问来源于stack exchange,提问作者Lingxi

