在解释volatile
关键字用法之前,先看看什么叫编译器优化。
编译器为了提升代码最终的执行效率,会进行一个非常重要的步骤,就是编译优化。
在一个线程中, 当读取一个变量时,为提高存取速度,编译器优化有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量值在该线程里发生改变时,会同时把变量的新值复制到该寄存器中,以便保持一致。
但是,当变量在因别的线程等而改变了内存中的值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。当该寄存器在因别的线程等而改变了值,原变量在内存中的值不会改变,从而造成应用程序读取的值和实际的变量值不一致。
该你上场了,volatile
关键字volatile
是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。而使用这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
简单来说,使用volatile
关键字是防止编译器对变量的优化而忽略了值发生改变。编译器在用到这个变量时必须每次都小心地从内存中重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面从代码来看看volatile
关键字的用法。
#include <iostream>
#include <stdio.h>
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 <iostream>
#include <stdio.h>
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
用在如下的几个地方:
- 一个中断服务子程序中会访问到的非自动变量
- 多线程应用中被几个任务共享的变量
- 并行设备的硬件寄存器(如:状态寄存器)
参考文献