简介
首先需要确定的几点:
1. volatile不能解决多线程的乱序执行的问题
2. volatile不是强制将修改后的值刷新回主内存,这种说法不够准确
3. 编译器在对代码进行编译时,会进行不同级别的优化,其中有一些优化是不利于代码的执行的,使用volatile可以避免其中的一些编译优化,比如寄存器优化
作用
- 易变形
对于非volatile变量,编译器会优化,将值缓存在寄存器中,对于a=func©,b = a+1,执行时,后面可以直接使用寄存器中的a。如果加了volatile变量,a=func©,a会被写回内存,后面在读取的时候也会重新把它从内存中读出来。
volatile的易变性指的就是,下条语句不会直接使用上一条语句对应volatile的寄存器内容,而是直接从内存中读取出来;
- 不可优化性
对于下图种情况,编译器认为a,b,c三个变量是无用的,可以进行常量替换,加上volatile之后,三个变量都会存在,且会将变量读入到寄存器中。保证程序员写在代码中的指令一定会被执行。
- 顺序性
编译器的基本优化原理:保证一段程序的输出,在优化前后无变化,比如:a=b+1,b=0;经过编译器优化可能变成”b=0;a=b+1",如果将变量B声明为volatile变量,也不会阻止编译器的优化,还是会出现乱序,但是如果把ab都设置为volatile变量,就不会出现乱序了。
○ 那么是否可以将所有的变量设置为volatile从而阻止指令的乱序呢?
不能,除了编译器优化还有CPU指令执行优化,这个需要使用合适的内存模型或者对应的硬件指令防止乱序执行。
使用场景
a. 并行设备的硬件寄存器需要加volatile,因为每次对它的读写都可能具有不同意义(存储器映射的硬件寄存器)
- 要对一个设备进行初始化,比如:此设备的某一个寄存器为0xff800000。for(i=0;i< 10;i++) *output = i;前面循环半天都是废话,对最后的结果毫无影响,因为最终只是将output这个指针赋值为9,省略了对该硬件IO端口反复读的操作。
b. 中断服务程序修改其他程序检测的变量需要加volatile
- 当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中读取变量副本,使得中断程序的操作被短路。
c. 多任务环境下,个任务之间的共享标志应该加volatile
- 可能会将变量读取到寄存器中,以后再取变量值的时候就直接从寄存器中取值;当内存变量或寄存器变量因为别的线程等而改变了值,该寄存器的值就不会相应改变,从而导致应用程序读取的值和实际的变量值不一致。
写得很清楚:
volatile关键字解析
C/C++ Volatile关键词深度剖析 - 流水灯 - 博客园 (cnblogs.com)
volatile关键字在多线程编程中起到确保内存可见性和禁止指令重排序的作用。它能保证共享变量的更新对所有线程可见,但无法解决并发控制问题。主要应用场景包括:并行设备的硬件寄存器、中断服务程序中的变量以及多线程环境下的共享标志。然而,volatile并不能阻止CPU指令执行的乱序,对于更严格的同步需求,需要依赖内存模型或硬件指令。

2818

被折叠的 条评论
为什么被折叠?



