Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

คุณสมบัติ volatile ใน C/C++: บอก Compiler อย่า Optimize ตัวแปรนี้

volatile เป็น Type Qualifier บอก Compiler ว่า ค่าของตัวแปรอาจเปลี่ยนแปลงได้ทุกเมื่อ โดยกระบวนการภายนอกที่ Compiler ไม่รู้จัก** จึงต้องไม่ Optimize (Cache ใน Register, Reorder, Remove) การ Access ตัวแปรนี้

Syntax


volatile int flag;
int volatile flag;        // เทียบเท่า
volatile int* ptr;        // Pointer to volatile int
int* volatile ptr;        // Volatile pointer to int (Pointer ตัวเอง Volatile)
volatile int* volatile ptr; // ทั้งคู่

เมื่อไหร่ต้องใช้ volatile?

Scenarioตัวอย่าง
Memory-Mapped I/O (Hardware Registers)GPIO, UART, Timer Registers
Global Variables แชร์กับ Interrupt Service Routine (ISR)Flag ที่ ISR Set, Main Loop Check
Global Variables แชร์ระหว่าง Threads (Basic)Flag สัญญาณ (แต่ควร用 Atomic/Mutex)
setjmp/longjmp ContextVariables ที่ต้องคงค่าระหว่าง Jump

ตัวอย่าง: Hardware Register


// Address 0x4000_0000 คือ GPIO Output Register
volatile uint32_t* GPIO_OUT = (volatile uint32_t*)0x40000000;

void set_pin(int pin) {
    *GPIO_OUT |= (1 << pin);  // Write: Compiler ต้อง Generate Write Instruction
}

int read_pin(int pin) {
    return (*GPIO_OUT >> pin) & 1; // Read: Compiler ต้อง Generate Read Instruction
}

ตัวอย่าง: ISR Flag


volatile bool interruptFlag = false;

void ISR_Timer() { // Interrupt Handler
    interruptFlag = true; // Write
}

int main() {
    while (!interruptFlag) { // Read: Compiler ไม่ Cache ใน Register
        // Wait...
    }
    // Interrupt Occurred
}

สิ่งที่ volatile ไม่ ทำ (Common Misconceptions)

MisconceptionReality
ทำให้ Thread-Safe❌ ไม่ให้ Atomicity, Memory Ordering, Visibility -> ใช้ std::atomic
ป้องกัน Race Condition❌ ไม่มี Synchronization
บังคับ Flush Cache❌ Compiler Level เท่านั้น (CPU Cache ไม่เกี่ยว)
เหมือน Atomic❌ ต่างกันสิ้นเชิง

volatile vs std::atomic (C++11)


// Shared Flag ระหว่าง Threads
volatile bool v_flag = false;     // ❌ ผิด: No Memory Ordering
std::atomic<bool> a_flag{false}; // ✅ ถูกต้อง: Sequential Consistency

// Hardware Register
volatile uint32_t* hw_reg = ...; // ✅ ถูกต้อง: Compiler Barrier
std::atomic<uint32_t>* hw_reg_atomic = ...; // ❌ ผิด: Atomic Operations บน HW Register ไม่ได้

สรุป

volatile ใช้สำหรับ Hardware Registers, ISR Flags, setjmp/longjmp บอก Compiler อย่า Optimize Access ไม่ใช่ สำหรับ Thread Synchronization (ใช้ std::atomic, Mutex) การเข้าใจขอบเขตการทำงานสำคัญมากสำหรับ Embedded และ Systems Programming