volatile ใน C++ มีความหมายเหมือน C: บอก Compiler ว่าตัวแปรอาจเปลี่ยนแปลงได้ "นอกเหนือจาก Control Flow ของโปรแกรม" จึงต้องไม่ Optimize การ Access
Syntax
volatile int flag;
int volatile flag; // เทียบเท่า
volatile int* ptr; // Pointer to volatile int
int* volatile ptr; // Volatile pointer to int
volatile int* volatile ptr; // ทั้งคู่
Use Cases ที่ถูกต้อง
- Memory-Mapped Hardware Registers: Address ที่ Map เข้ากับ Hardware Device
- Variables แชร์กับ Interrupt Service Routines (ISR): Flag, Counter
- Variables ใน
setjmp/longjmpContext: ป้องกัน Register Caching - Signal Handlers (C):
volatile sig_atomic_t
ตัวอย่าง: Hardware Register
// STM32 GPIO Example
#define GPIOA_BASE 0x48000000
#define GPIO_ODR_OFFSET 0x14
volatile uint32_t* GPIOA_ODR = (volatile uint32_t*)(GPIOA_BASE + GPIO_ODR_OFFSET);
void setPin(int pin) {
*GPIOA_ODR |= (1U << pin); // Compiler ต้อง Generate STR Instruction
}
int readPin(int pin) {
return (*GPIOA_ODR >> pin) & 1U; // Compiler ต้อง Generate LDR Instruction
}
ตัวอย่าง: ISR Flag
#include <atomic> // สำหรับ Context อื่น
volatile bool timerExpired = false; // ISR เขียน, Main อ่าน
extern "C" void TIM2_IRQHandler() { // ISR
timerExpired = true;
}
int main() {
while (!timerExpired) { // Compiler ไม่ Cache timerExpired ใน Register
// Do work
}
// Timer Expired
}
⚠️ volatile ≠ Thread Synchronization
| Feature | volatile | std::atomic |
|---|---|---|
| Compiler Optimization Barrier | ✅ | ✅ |
| Atomicity (Indivisible Operations) | ❌ | ✅ |
| Memory Ordering (Happens-Before) | ❌ | ✅ |
| Cache Coherence | ❌ | ✅ (Hardware) |
| Use Case | Hardware, ISR, setjmp | Thread Communication |
ผิด: ใช้ volatile สำหรับ Thread Flag
// ❌ WRONG: Data Race, No Memory Ordering
volatile bool ready = false;
int data = 0;
void producer() {
data = 42;
ready = true; // Store ไม่มี Release Semantics
}
void consumer() {
while (!ready) {} // Load ไม่มี Acquire Semantics
use(data); // อาจเห็น data = 0 (Reordering)!
}
ถูกต้อง: ใช้ std::atomic
// ✅ CORRECT
std::atomic ready{false};
int data = 0;
void producer() {
data = 42;
ready.store(true, std::memory_order_release);
}
void consumer() {
while (!ready.load(std::memory_order_acquire)) {}
use(data); // รับประกันว่าเห็น data = 42
}
สรุป
volatile ใช้สำหรับ Hardware Access, ISR, setjmp/longjmp เท่านั้น ห้ามใช้สำหรับ Thread Synchronization (Data Race, No Memory Order) ใช้ std::atomic, std::mutex, std::condition_variable แทนสำหรับ Multi-threading