遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

volatile 是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,

基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。

下面是volatile变量的几个例子:

  1).并行设备的硬件寄存器(如:状态寄存器)

  2).一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

  3).多线程应用中被几个任务共享的变量

const volatile int i=10;这行代码有没有问题?如果没有,那i到底是什么属性?

木有问题  举个例子是只读的状态寄存器。

它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

const和volatile这两个类型限定符不矛盾。

const表示(运行时)常量语义:被const修饰的对象在所在的作用域无法进行修改操作,

                                                      编译器对于试图直接修改const对象的表达式会产生编译错误。

volatile表示“易变的”,即在运行期对象可能在当前程序上下文的控制流以外被修改

                                       (例如多线程中被其它线程修改;对象所在的存储器可能被多个硬件设备随机修改等情况):

                                          被volatile修饰的对象,编译器不会对这个对象的操作进行优化。

一个对象可以同时被const和volatile修饰,表明这个对象体现常量语义,但同时可能被当前对象所在程序上下文意外的情况修改。

 

 

使用举例:易变性

求平方

int square(volatile int *ptr)

{

  int a,b;

  a = *ptr;

  b = *ptr;

  return a * b;

}

这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:  

int square(volatile int *ptr)

{  

int a,b;  

a = *ptr; 

b = *ptr;

return a * b;

}

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:  

long square(volatile int *ptr)  

{  

int a;  

a = *ptr;  

return a * a;  

}

使用举例:防优化(debug版本不会做优化 使用release版本实验)

int i=10;  

int a = i;  

printf("i= %d",a);  

//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道  

_asm

{  

mov dword ptr [ebp-4], 20h   //改为 i=20h 则不行 详见下边的优化方法 

}  

int b = i;  

printf("i= %d",b);  

}  release版本下输出为10 10进行了优化(因为 上边那段汇编语句 已经在内存中把i的值改变了 而这里却没有变化)

优化方法

由于编译器发现两次从 i 读数据的代码之间的代码没有对 i 进行过操作(编译器没发现),它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

使解决方法  用volatile关键字后即可  输出结果如下:  i = 10  i = 32(重新去内存读取数据) 保证了 "同步"

 

Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。(锁的概念)