避免编译器对生成的机器码进行优化,从而可以提供对特殊地址的稳定访问
功能
- 对声明为volatile的变量进行的任何操作都不会被优化器去除,即使看起来没有任何意义(例如,连续多次对某个变量赋相同的值),因为它可能会被编译时未知的某个外部设备或线程使用
- 被声明为volatile的变量不会被编译器优化到寄存器中,每次操作都保证在内存中进行
- 在不同表达式内的volatile变量间的操作顺序不会被优化器调换,即编译器保证多个volatile变量在sequence point之间的访问顺序不会被优化和调整
不能解决的问题
- 保证变量读写的原子性(如 +=)
- 确保变量操作发生在主内存中,而不是Cache中
- 确保CPU不会乱序执行指令
volatile用在如下的几个地方:
- 中断服务程序中修改的供其它程序检测的变量需要加volatile;
- 多任务环境下各任务间共享的标志应该加volatile; 多任务环境下各任务间共享的标志应该加volatile;
- 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
线程下的volatile
有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:
volatile BOOL bStop = FALSE;
// 在一个线程中:
while( !bStop ) { ... }
bStop = FALSE;
return;
//在另外一个线程中,要终止上面的线程循环:
bStop = TRUE;
while( bStop ); //等待上面的线程终止,
如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。
这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:
int nMyCounter = 0;
for(; nMyCounter<100;nMyCounter++)
{
...
}
在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter -= 1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不同步。