volatile
volatile是一个类型修饰符(type specifier)。
volatile的作用是:表明被修饰的变量可能被意外的修改,同时阻止编译器对访问该变量的代码进行优化。造成意外修改的因素可能有:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
编译器优化代码的例子:
a = 0x55;
a = 0x56;
a = 0x57;
a = 0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有
a=0x58(即忽略前三条语句,只产生一条机器代码)。
如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(产生四条代码).
for
(
int
i=0; i<100000; i++);//编译器肯定要把它优化掉,根本就不执行,int 前加上volatile就不会被优化掉了
由于访问寄存器的速度要快过内存,所以编译器一般都会作减少读写内存的优化,先把变量的值读入寄存器,以后使用该变量时都直接从寄存
器读值。
作为C++程序员,我们可以先暂时只关注第3种意外变量值的因素: 多线程应用中被几个任务共享的变量。
网上很多例子都说被几个多线程共享的变量需要使用volatile关键字,其实并不是这样的:
下面这段话转自知乎:
C/C++多线程编程中不要使用volatile。
(注:这里的意思指的是指望volatile解决多线程竞争问题是有很大风险的,除非所用的环境系统不可靠才会为了保险加上volatile,
或者是从极限效率考虑来实现很底层的接口。这要求编写者对程序逻辑走向很清楚才行,不然就会出错)
C++11标准中明确指出解决多线程的数据竞争问题应该使用原子操作或者互斥锁。
https://www.zhihu.com/question/31459750/answer/52069135
C和C++中的volatile并不是用来解决多线程竞争问题的,而是用来修饰一些因为程序不可控因素导致变化的变量,比如访问底层硬件设备的变量,
以提醒编译器不要对该变量的访问擅自进行优化。
多线程场景下可以参考《Programming with POSIX threads》的作者Dave Butenhof对
Why don't I need to declare shared variables VOLATILE?
这个问题的解释:
comp.programming.threads FAQ
如果光对共享变量使用volatile修饰而在可能存在竞争的操作中不加锁或使用原子操作对解决多线程竞争没有任何卵用,
因为volatile并不能保证
操作的原子 性,在读取、写入变量的过程中仍然可能被其他线程打断导致意外结果发生。