volatile关键字
c/c++中的一个常见,驱动调试中相当常用的一个关键字
总结一下volatile关键字的作用:
1、多线程中防止编译器优化
#include <stdio.h> #include <stdlib.h> #include <pthread.h> volatile int flag = 0; // 定义一个 volatile 变量 void *thread_func(void *arg) { while (flag == 0) { // 在循环中检查 flag 的值 } printf("Flag is now 1, thread exiting.\n"); pthread_exit(NULL); } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_func, NULL); // 模拟一些工作 sleep(1); printf("Setting flag to 1...\n"); flag = 1; // 主线程设置 flag 的值为 1 pthread_join(tid, NULL); return 0; }
如果上面的demo没有使用 volatile 的情况下,编译器可能会对 flag 进行寄存器缓存,或者对读取操作进行重排,以优化代码执行的效率。这意味着,在循环中检查 flag 的值时,可能会使用缓存中的旧值,而不是实际的最新值。因此,即使主线程将 flag 的值设置为 1,循环仍然可能会继续执行,导致程序无法正确地退出。
2、硬件IO操作
驱动调试中,对寄存器的读取是十分常见的,下面分别是读寄存器和写寄存器的方式,将addr转换成volatile unit32_t型,这样通过取值符号取值时每次都能够正常读取addr的值,防止系统优化直接读取缓存中的值
#define read_reg(addr) (*((volatile uint32_t *)(addr))) #define write_reg(addr, val) (*((volatile uint32_t *)(addr)) = ((uint32_t) (val)))
3、自旋锁和原子操作的实现
内核中的自旋锁和一些原子操作通常使用 volatile 变量来实现。这些操作需要保证在多线程环境下对共享资源的互斥访问,以及对操作的原子性要求,因此使用 volatile 变量能够确保相关操作的正确性和稳定性。
原子操作使用atomic_t就是volatile实现的:
typedef struct { volatile int counter; } atomic_t;