volatile关键字是一种类型修饰符

volatile int a;

volatile原义:

A situation that is volatile is likely to change suddenly and unexpectedly.

  • likely:可能的。这意味着被 volatile 形容的对象「有可能也有可能不」发生改变,因此我们不能对这样的对象的状态做出任何假设。
  • suddenly:意味着被 volatile 形容的对象可能发生瞬时改变。
  • unexpectedly:意味着被 volatile 形容的对象可能以各种不可预期的方式和时间发生更改。

因此,volatile 其实就是告诉我们,被它修饰的对象出现任何情况都不要奇怪,我们不能对它们做任何假设。

程序中volatile的含义

1. volatile修饰的对象可能受到程序之外的因素影响

这里说的程序之外的因素影响可以是操作系统、硬件或者其它线程等。

int a = 0;
int b = a;

在上述代码中,当执行b = a语句时,编译器会判断在a赋值以后就没有改变过a的值, 因此会把寄存器中暂存的a的值给b,而不是去a的内存地址处去读取a再赋值给b。

一般情况这样是没问题的,但是当有中断程序或者别的进程去修改了a的值,那寄存器里暂存的a就会和内存里存放的a不一致。

加了volatile限定符,每次使用a时都会去a的内存地址处读取a,这样能保证每次读取的a都是最新的值;但同时会导致效率降低,因为读取内存的速度远低于读取寄存器的速度。

2. volatile修饰的对象不允许被编译器optimized out

volatile int num;
num = 1;
printf("num is: %d", num);

在上述代码中,如果变量 num 没有声明为 volatile 类型,则编译器在编译过程中就会对其进行优化,直接使用常量“1”进行替换。

当使用 volatile 进行声明后,编译器则不会对其进行优化。

3. volatile修饰的对象能够保证不会被编译器调整执行顺序

编译器编译时可能会调整代码的执行顺序

编译器虽然能保证不对volatile变量执行顺序进行优化,但是不能保证对volatile 变量与非 volatile 变量之间的操作的执行顺序不优化。

但是,volatile只作用在编译器上,但我们的代码最终是要运行在 CPU 上的。尽管编译器不会调整执行顺序,但 CPU 的乱序执行(out-of-order execution)技术还是可能导致代码的执行顺序被改变。

volatile用法

volatile 只在三种场合下是合适的:

  • 和信号处理(signal handler)相关的场合;
  • 和内存映射硬件(memory mapped hardware)相关的场合;
  • 和非本地跳转(setjmp 和 longjmp)相关的场合。

volatile与多线程

volatile不能解决多线程中的问题