Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Từ khóa volatile trong C

volatile là chỉ định kiểu (type qualifier) nói với compiler: "Giá trị của biến này có thể thay đổi bất cứ lúc nào bởi bên ngoài, đừng tối ưu hóa truy cập đến nó."

Cú pháp


volatile int a;
int volatile a;  // Tương đương
volatile int* ptr;       // Con trỏ TO dữ liệu volatile
int* volatile ptr;       // Con trỏ VOLATILE (hiếm dùng)
volatile int* volatile ptr; // Cả hai

Tác động của volatile

Ví dụ: Không có vs Có volatile


// Không volatile - compiler có thể tối ưu: đọc value một lần, giữ trong register
int main() {
    int value = 0;
    while (value == 0) {
        // Compiler có thể biến thành: if (value == 0) while(1); 
    }
}

// Có volatile - compiler PHẢI đọc bộ nhớ mỗi lần kiểm tra
int main() {
    volatile int value = 0;
    while (value == 0) {
        // Luôn đọc từ địa chỉ value
    }
}

Khi nào dùng volatile?

  1. Thanh ghi phần cứng (Memory-mapped I/O): Đọc/ghi thanh ghi thiết bị
  2. Biến chia sẻ với ISR (Interrupt Service Routine): Ngắt sửa đổi biến
  3. Biến chia sẻ giữa threads (C++11+): Thay bằng std::atomic
  4. setjmp/longjmp: Biến cục bộ thay đổi sau longjmp

Ví dụ: Memory-mapped register


// Giả sử địa chỉ 0x40000000 là thanh ghi GPIO
#define GPIO_PORT (*(volatile uint32_t*)0x40000000)

void set_pin(int pin) {
    GPIO_PORT |= (1 << pin);   // Ghi - không bị loại bỏ
}

int read_pin(int pin) {
    return (GPIO_PORT >> pin) & 1;  // Đọc - luôn lấy giá trị mới
}

Ví dụ: Biến chia sẻ với ISR


volatile int interrupt_flag = 0;

void ISR_timer() {
    interrupt_flag = 1;  // Ngắt đặt cờ
}

int main() {
    while (!interrupt_flag) {
        // Chờ ngắt - luôn kiểm tra bộ nhớ
    }
    // Xử lý sự kiện
}

volatile KHÔNG phải là

Tối ưu hóaKhông có volatileCó volatile
Cache vào registerCóKhông (đọc/ghi bộ nhớ mỗi lần)
Loại bỏ đọc/ghi dư thừaCóKhông
Sắp xếp lại lệnh (reorder)CóKhông (giữ thứ tự)
Hiểu lầmThực tế
Làm cho phép toán atomicKhông! Dùng std::atomic (C++11) hoặc atomic builtin
Đồng bộ hóa threadKhông! Dùng mutex, atomic, condition_variable
Ngăn reorder giữa các threadChỉ ngăn reorder trong cùng thread

C++11+: Thay thế cho multi-threading


#include <atomic>
#include <thread>

std::atomic<int> shared_counter{0};  // Thread-safe, atomic

void worker() {
    for (int i = 0; i < 1000; ++i) shared_counter++;
}

Tóm tắt

  • volatile: "Đừng cache, đừng loại bỏ, đừng reorder truy cập biến này"
  • Dùng cho: Hardware register, ISR shared variable, setjmp/longjmp
  • KHÔNG dùng cho thread synchronization (dùng std::atomic, mutex)
  • Không đảm bảo atomicity hay memory ordering giữa threads