SoFunction
Updated on 2025-04-13

Detailed explanation of the keyword volatile in C++

1. The role of volatile keywords

Under normal circumstances, the compiler will optimize the code.

For example, if a variable does not change in a piece of code, the compiler may cache it into a register and no longer read from memory. But in some cases, the value of the variable may beOutside the programChanges occur, such as multithreaded access, hardware registers, asynchronous events, etc.

If the compiler optimizes these variables, it may cause unpredictable errors in the program.

Problems that volatile can solve:

  • Prevent compiler optimization so that variables read the latest value from memory every time
  • Make sure that the value of the variable is not cached by the register
  • Suitable for multithreading, hardware registers and other scenarios

Problems that volatile cannot be solved:

  • volatile cannot guarantee thread safety
  • volatile cannot guarantee the atomicity of multiple operations
  • To implement thread synchronization, you should use std::atomic or mutex

2. Use scenarios of volatile keywords

1. Multi-threaded shared variables

In a multithreaded environment, one thread may modify the variable, while another thread needs to detect the change of the variable.volatileMake sure that the thread reads the latest value each time, not the compiler optimized cached value.

Example:

#include <iostream>
#include <thread>

volatilebool stopFlag = false;  // Use the volatile keyword
void worker() {
    while (!stopFlag) {  // If there is no volatile, the old value may be read all the time        std::cout << "Worker is running..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    std::cout << "Worker stopped." << std::endl;
}

int main() {
    std::thread t(worker);
    
    std::this_thread::sleep_for(std::chrono::seconds(3));
    stopFlag = true;  // Another thread modify stopFlag
    ();
    return0;
}

explain:

  • volatile bool stopFlagmake sureworkerThread can detectmainThread pairstopFlagmodification.
  • If not usedvolatile, the compiler may optimizestopFlagread, letworkerThread infinite loop.
  • butvolatileNo thread safety guaranteedIf multiple threads are involved in synchronization, it is recommended to usestd::atomic<bool>replace.

2. Access hardware registers

In embedded development, hardware registers (such as I/O ports, device status registers, etc.) are usually required, and the values ​​of these registers may change at any time. usevolatileMake sure that every visit is up to date.

Example (embedded system):

#define STATUS_REGISTER (*(volatile unsigned int*)0x40001000)

void checkStatus() {
    while (STATUS_REGISTER &amp; 0x01) {  // Read the status register        // Wait for the state to change    }
}

explain:

  • volatilemake sureSTATUS_REGISTER Will not be optimized by the compiler, read the latest value from the hardware register every time you access.
  • existEmbedded developmentIn, visitI/O ports, sensor dataWhen it is usually necessaryvolatile

3. Prevent compiler optimization

In some cases, we may need to insert one into the codeEmpty loopto perform a short delay, but if not usedvolatile, the compiler may directly optimize this loop, causing the code to not execute as expected.

Example:

void delay() {
    for (volatile int i = 0; i &lt; 1000000; i++);  // Prevent optimization of loop loss}

explain:

  • volatileEnsure loop variablesi Read from memory every time, will not be optimized by the compiler.
  • This usage is commonTime delay, busy waitingetc.

4. Handle asynchronous events

Some programs may handle asynchronous events (e.g.InterruptorSignal), the value of the variable may be modified at an unknown point in time. usevolatileEnable the main program to correctly read the latest value of the variable.

Example (simulated interrupt processing):

volatile bool interruptFlag = false;  // Interrupt flag
void interruptHandler() {  // Assume it is an interrupt service function    interruptFlag = true;
}

void checkInterrupt() {
    while (!interruptFlag) {
        // Wait for an interrupt to occur    }
    std::cout &lt;&lt; "Interrupt received!" &lt;&lt; std::endl;
}

explain:

  • interruptFlagProbably inInterrupt handlerwas modified, sovolatileMake sure the latest value is read every time.
  • If notvolatile, the compiler may be optimizedwhile (!interruptFlag)This part of the code turns it into a dead loop.

3. volatile vs std::atomic

In multithreaded programming,volatileJustPrevent compiler optimization,butcannotEnsure thread safety. For example:

volatile int counter = 0;

void increment() {
    for (int i = 0; i &lt; 100000; i++) {
        counter++;  // It's still not thread-safe    }
}

question:

  • counter++ Not an atomic operation, it containsRead, add, write backThree steps, which may lead to data competition in a multi-threaded environment.

Recommended usestd::atomicreplace:

#include &lt;atomic&gt;

std::atomic&lt;int&gt; counter = 0;

void increment() {
    for (int i = 0; i &lt; 100000; i++) {
        counter++;  // Thread safety    }
}

Summarize:

  • volatileSuitable for preventing optimization, but does not guarantee thread safety.
  • std::atomicIt can not only prevent optimization, but also ensure the atomicity of the operation.

4. Experience

Use scenarios

volatile

The role of

Multithreaded variables

Make sure that every read is the latest value (but not thread-safe)

Hardware Registers

Access I/O ports or status registers to prevent compiler optimization

Prevent optimization

Make variables not cached by registers, ensuring that loops and other codes are not optimized

Asynchronous Events

Handle asynchronous situations such as interrupts and signals to ensure that the main program correctly reads the latest value

V. Conclusion

  • volatileApplicable toMultithreading, hardware registers, asynchronous eventsScenarios, but itNo thread safety guaranteed
  • existMulti-threaded environmentDown,Recommended use std::atomicInsteadvolatile**,becausestd::atomicCan guaranteeThread safety and visibility
  • existEmbedded developmentmiddle,volatileStillBest choice for accessing hardware registers

The above is personal experience. I hope you can give you a reference and I hope you can support me more.