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;
 
posted @ 2024-02-25 01:37  lethe1203  阅读(15)  评论(0编辑  收藏  举报