详解volatile 关键字

一、前言

1. 编译器优化介绍

  • 硬件优化

    • 内存访问速度低于 CPU 处理速度,使用硬件高速缓存(Cache)加速内存访问。
    • 现代 CPU 指令可以乱序执行,以充分利用指令流水线,提高执行速度。
  • 软件优化

    • 程序员优化:在编写代码时进行优化。
    • 编译器优化
      • 将内存变量缓存到寄存器。
      • 调整指令顺序,充分利用 CPU 指令流水线,如重新排序读写指令。
      • 对常规内存进行优化时,这些优化通常是透明且高效的。
  • 内存屏障

    • 解决编译器优化或硬件重新排序引起的问题。
    • 内存屏障确保特定顺序执行的操作之间的顺序性。
    • Linux 提供了一个宏函数 void Barrier(void),通知编译器插入一个内存屏障(仅对编译器有效,对硬件无效)。

2. volatile 关键字

  • 数据流分析
    • 编译器技术,通过分析程序中变量的赋值、使用和失效位置,进行常量合并、传播等优化。
    • 有时这些优化不符合程序需求,此时使用 volatile 关键字禁止这些优化。

二、volatile 详解

1. volatile 的定义和作用

  • 定义:“易变的”。
  • 作用
    • 编译器通常通过减少内存访问来优化性能,但这可能会导致读取脏数据。
    • 使用 volatile 声明的变量,每次访问都重新从内存读取数据。
    • 禁止编译器对访问 volatile 变量的代码进行优化,确保对特殊地址的稳定访问。

2. 例子解析

1. 禁止编译器优化

int *ip = ...; //设备地址
*ip = 1; //第一个指令
*ip = 2; //第二个指

  • 编译器优化后可能变为:

int *ip = ...;
*ip = 2;

  • 使用 volatile 禁止优化:

volatile int *ip = ...;
*ip = 1;
*ip = 2;

2. volatile 变量每次都从内存读取

volatile char a;
a = 0;
while (!a) {
    // do some things;
}
doother();

  • 如果没有 volatiledoother() 可能不会被执行。

3. volatile 变量的使用场景

1. 中断服务程序修改的变量

static int i = 0;
int main(void) {
    ...
    while (1) {
        if (i) dosomething();
    }
}

void ISR_2(void) {
    i = 1;
}

 

  • i 需要用 volatile 修饰,确保在中断服务程序修改时,主程序能正确读取。
2. 多任务环境下共享的标志
  • 多任务间共享的标志变量需要加 volatile 修饰。
3. 存储器映射的硬件寄存器
volatile int *output = (volatile unsigned int *)0xff800000;
int init(void) {
    int i;
    for (i = 0; i < 10; i++) {
        *output = i;
    }
}
  • 对外部设备初始化时,需要 volatile 确保每次对寄存器的写操作都生效。

4. 常见问题

1. const 和 volatile 同时使用
  • 可以,例如只读的状态寄存器:
    const volatile int status;
    
2. volatile 指针
  • 可以,当中断服务程序修改指向缓冲区的指针时:
    const volatile int status;
    

5. volatile 的本质

1. 编译器优化
  • 为提高存取速度,编译器可能将变量缓存到寄存器中。
  • volatile 禁止这种优化,确保每次都从原始内存地址读取变量。
2. 解释
  • volatile 应解释为“直接存取原始内存地址”。

6. 函数示例

错误示例
int square(volatile int *ptr) {
    return *ptr * *ptr;
}
  • 可能导致错误,因为 *ptr 的值可能在两次读取之间改变。
正确示例
long square(volatile int *ptr) {
    int a;
    a = *ptr;
    return a * a;
}

注意事项

  • 频繁使用 volatile 可能增加代码尺寸并降低性能,因此应合理使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值