跳到主要内容

认识volatile

前言:这部分内容涉及到汇遍的知识,所以会补充一些汇编的知识。

补充

变量可能会因为编译器的优化从缓存中读取而导致值被意外的改变。要正确处理这个值,需要保证从内存中读取这个值才能保证正确。

原因: 在单任务环境中,如果一个函数体内部在两次读取变量值之间的语句没有对变量值进行修改,那么编译器就会设法对可执行代码进行优化。由于访问寄存器的速度要比 RAM(从 RAM 中读取变量的值到寄存器中)快,所以以后只要变量的值没有改变,就一直从寄存器中读取变量的值,而不对 RAM 进行访问。 而在多任务环境中,虽然一个函数体内部在两次读取变量值之间没有对变量的值进行修改,但是该变量仍然有可能被其他的程序(如中断程序、另外的线程等)修改,如果这时还是从寄存器而不是从 RAM 中读取,就会出现被修改的变量值不能及时得到反映的问题。

问题复现

#include<iostream>
using namespace std;
int main(int arge, char * argv[])
{
int i = 10;
int a = i;
cout << a << endl;
_asm //在VS 2017 的环境下内联汇编代码
{
mov dword ptr [ebp - 4],70 //修改变量i的值
}
int b = i;
cout << b << endl;
getchar();//暂停程序执行
}

在这段代码中,输出如下:

10
10

可以看到,内联的汇编代码已经修改了i的值,但i的变化并没有反馈到b中。

认识volatile

volatile是易变的意思,在C/C++语言中较少使用。用于解决变量在共享的情况下容易出现读取错误的问题

上面的问题就可以用volatile解决。也就是

--- int i = 10;
+++ volatile int i = 10;

用volatile通知编译器这个变量是不稳定的,防止编译器对这个变量进行优化。

应用

1.多线程

在多线程共享一个变量的时候,保证每一次都从内存中真正进行读取。防止因为缓存在寄存器中从而导致值未被及时同步造成错误

2.并行设备的寄存器

例如一个设备进行初始化需要对某个I/O端口进行1-9的赋值,则以下代码段:

for (i = 0;i < 10; i++)
{
* output = i;
}

则该代码段在优化后,指针会被直接赋值9,从而出现问题。

3. 嵌入式编程

避免编译器优化所带来的执行错误。