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
| Tối ưu hóa | Không có volatile | Có volatile |
| Cache vào register | Có | Không (đọc/ghi bộ nhớ mỗi lần) |
| Loại bỏ đọc/ghi dư thừa | Có | Không |
| Sắp xếp lại lệnh (reorder) | Có | Không (giữ thứ tự) |
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?
- Thanh ghi phần cứng (Memory-mapped I/O): Đọc/ghi thanh ghi thiết bị
- Biến chia sẻ với ISR (Interrupt Service Routine): Ngắt sửa đổi biến
- Biến chia sẻ giữa threads (C++11+): Thay bằng
std::atomic
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à
| Hiểu lầm | Thực tế |
| Làm cho phép toán atomic | Không! Dùng std::atomic (C++11) hoặc atomic builtin |
| Đồng bộ hóa thread | Không! Dùng mutex, atomic, condition_variable |
| Ngăn reorder giữa các thread | Chỉ 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