1、什么是volatile
这是在MSDN中对关键字“volatile”的说明:
The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.
volatile关键字是一种限定符用来声明一个对象在程序中可以被语句外的东西修改,比如操作系统、硬件或并发执行线程。
遇到该关键字,编译器不再对该变量的代码进行优化,不再从寄存器中读取变量的值,而是直接从它所在的内存中读取值,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
下面写个代码测试一下volatile关键字
注:VC6.0中一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无 volatile 关键字,对程序最终代码的影响:
#include <stdio.h>
void main()
{
int i = 10;
int a = i;
printf("i = %d", a);
// 下面汇编语句的作用就是改变内存中 i 的值
// 但是又不让编译器知道
__asm {
mov dword ptr [ebp-4], 20h
}
int b = i;
printf("i = %d", b);
}
结果
在 Debug 版本模式运行程序:
i = 10 i = 32
在Release版本模式下运行程序:
i = 10 i = 10
上述 输出的结果明显表明,Release 模式下,编译器对代码进行了优化,第二次没有输出正确的 i 值。下面,我们把 i 的声明加上 volatile 关键字(在这里不再贴代码,就是上面的代码i前面加上volatile)
结果显示:在Debug和Release版本模式下运行程序
i = 10 i =32
这就是表示volatile关键字发挥了作用
2、volatile在哪儿使用
一般说来,volatile用在如下的几个地方:
(1)、中断服务程序中修改的供其它程序检测的变量需要加volatile;
(2)、多任务环境下各任务间共享的标志应该加volatile;
(3)、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2 中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
3、多线程下的volatile
当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:
volatile BOOL bStop = FALSE;
// (1) 在一个线程中:
while( !bStop ) { ... }
bStop = FALSE;
return;
//(2) 在另外一个线程中,要终止上面的线程循环:
bStop = TRUE;
while( bStop ); //等待上面的线程终止,
如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。