您的位置:首页 > 编程语言 > C语言/C++

读c语言深度剖析 -- volatile

2011-06-23 15:53 211 查看
遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
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 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。(锁的概念)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息