在解释volatile关键字用法之前,先看看什么叫编译器优化。
编译器为了提升代码最终的执行效率,会进行一个非常重要的步骤,就是编译优化。
在一个线程中, 当读取一个变量时,为提高存取速度,编译器优化有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量值在该线程里发生改变时,会同时把变量的新值复制到该寄存器中,以便保持一致。
但是,当变量在因别的线程等而改变了内存中的值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。当该寄存器在因别的线程等而改变了值,原变量在内存中的值不会改变,从而造成应用程序读取的值和实际的变量值不一致。
该你上场了,volatile
关键字volatile是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。而使用这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
简单来说,使用volatile关键字是防止编译器对变量的优化而忽略了值发生改变。编译器在用到这个变量时必须每次都小心地从内存中重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面从代码来看看volatile关键字的用法。
#include
#include
int main()
{
int i = 12;
int a = i;
std::cout << "i = " << a << std::endl;
// 下面汇编语句的作用就是改变内存中 i 的值
// 但是又不让编译器知道
__asm {
mov dword ptr[ebp - 4], 20h
}
int b = i;
std::cout << "i = " << b << std::endl;
return 0;
}
若是编译器开启优化,优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对 i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。
VS2019中Debug x86/Release x86输出结果一致
i = 12
i = 12
但是,网上的帖子说,一般调试模式没有进行代码优化。所以为什么这里都是开启优化的结果呢?
Release x86版本运行程序,把 i 的声明加上 volatile 关键字
#include
#include
int main()
{
volatile int i = 12;
int a = i;
std::cout << "i = " << a << std::endl;
// 下面汇编语句的作用就是改变内存中 i 的值
// 但是又不让编译器知道
__asm {
mov dword ptr[ebp - 4], 20h
}
int b = i;
std::cout << "i = " << b << std::endl;
return 0;
}
输出结果
i = 12
i = 32
一般说来,volatile用在如下的几个地方:
参考文献