c++中volatile详解
1. 为什么用volatile?
C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明:
A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:
| 1 | volatileinti=10; | 
| 2 | inta = i; | 
| 3 | ... | 
| 4 | // 其他代码,并未明确告诉编译器,对 i 进行过操作 | 
| 5 | intb = i; | 
volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。注意,在 VC 6 中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无 volatile 关键字,对程序最终代码的影响:
输入下面的代码:
| 01 | #include <stdio.h> | 
| 02 | 
| 03 | voidmain() | 
| 04 | { | 
| 05 |     inti = 10; | 
| 06 |     inta = i; | 
| 07 | 
| 08 |     printf("i = %d", a); | 
| 09 | 
| 10 |     // 下面汇编语句的作用就是改变内存中 i 的值 | 
| 11 |     // 但是又不让编译器知道 | 
| 12 |     __asm { | 
| 13 |         mov dword ptr [ebp-4], 20h | 
| 14 |     } | 
| 15 | 
| 16 |     intb = i; | 
| 17 |     printf("i = %d", b); | 
| 18 | } | 
然后,在 Debug 版本模式运行程序,输出结果如下:
i = 10
i = 32
然后,在 Release 版本模式运行程序,输出结果如下:
i = 10
i = 10
输出的结果明显表明,Release 模式下,编译器对代码进行了优化,第二次没有输出正确的 i 值。下面,我们把 i 的声明加上 volatile 关键字,看看有什么变化:
| 01 | #include <stdio.h> | 
| 02 | 
| 03 | voidmain() | 
| 04 | { | 
| 05 |     volatileinti = 10; | 
| 06 |     inta = i; | 
| 07 | 
| 08 |     printf("i = %d", a); | 
| 09 |     __asm { | 
| 10 |         mov dword ptr [ebp-4], 20h | 
| 11 |     } | 
| 12 | 
| 13 |     intb = i; | 
| 14 |     printf("i = %d", b); | 
| 15 | } | 
分别在 Debug 和 Release 版本运行程序,输出都是:
i = 10
i = 32
这说明这个 volatile 关键字发挥了它的作用。其实不只是“内嵌汇编操纵栈”这种方式属于编译无法识别的变量改变,另外更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方: 
1) 中断服务程序中修改的供其它程序检测的变量需要加volatile; 
2) 多任务环境下各任务间共享的标志应该加volatile; 
3) 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
2.volatile 指针
和 const 修饰词类似,const 有常量指针和指针常量的说法,volatile 也有相应的概念:
- 修饰由指针指向的对象、数据是 const 或 volatile 的: - 1- const- char- * cpch;- 2- volatile- char- * vpch;- 注意:对于 VC,这个特性实现在 VC 8 之后才是安全的。 
- 指针自身的值——一个代表地址的整数变量,是 const 或 volatile 的: - 1- char- *- const- pchc;- 2- char- *- volatile- pchv;
注意:(1) 可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。
          (2) 除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。
              (3) C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。
3. 多线程下的volatile
有些变量是用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的值,就不会死循环了。
    这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:  
  ...  
  int  nMyCounter  =  0;  
  for(;  nMyCounter<100;nMyCounter++)  
  {  
  ...  
  }  
  ...  
   在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter  -=  1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不同步。
c++中volatile详解的更多相关文章
- Java中Volatile详解
		当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写.这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的 ... 
- 黑马-----内存模型和volatile详解
		黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA线程-内存模型和volatile详解 一.单核内存模型 1.程序运行时,将临时数据存放到Cache中 2.将CPU计算所 ... 
- Java并发关键字Volatile 详解
		Java并发关键字Volatile 详解 问题引出: 1.Volatile是什么? 2.Volatile有哪些特性? 3.Volatile每个特性的底层实现原理是什么? 相关内容补充: 缓存一致性协议 ... 
- winxp计算机管理中服务详解
		winxp计算机管理中服务详解01 http://blog.sina.com.cn/s/blog_60f923b50100efy9.html http://blog.sina.com.cn/s/blo ... 
- cocos2dx常见的46中+22中动作详解
		cocos2dx常见的46中+22中动作详解 分类: iOS2013-10-16 00:44 1429人阅读 评论(0) 收藏 举报 bool HelloWorld::init(){ ///// ... 
- Android中Context详解 ---- 你所不知道的Context
		转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好, ... 
- iOS中-Qutarz2D详解及使用
		在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ... 
- 【转】declare-styleable的使用(自定义控件) 以及declare-styleable中format详解
		原文网址:http://www.cnblogs.com/622698abc/p/3348692.html declare-styleable是给自定义控件添加自定义属性用的 1.首先,先写attrs. ... 
- Python中dict详解
		from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ... 
随机推荐
- UVA 322 ships  (POJ 1138)
			题目地址: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ... 
- Socket开发时,Available为0,实际还有数据的问题
			这段时间处理Socket通讯,比如文件传输,通常代码如下: string filename = @"c:\abc.txt"; // 发送文件名字符串长度(测试代码,实际请传输字符串 ... 
- 转换函数CONVERSION_EXIT_TSTRN_OUTPUT
			CONVERSION_EXIT_TSTRN_OUTPUT 在路线表TVRO中字段TDVZND 运输提前时间,取出来的数值没有转换,需要此函数进行转换.如14400,000 转换后为14,400:00 ... 
- 有没有安全的工作?(99条评论)——结论是没有一劳永逸的工作,要终身学习,IT业刚出道和老手还是有区别的(同样对于新技术,薪资可能是个问题)
			作者: 阮一峰 日期: 2015年12月15日 如果你经常使用互联网,可能知道有一种东西叫做Flash. 它是一种软件,用来制作网页游戏.动画,以及视频播放器.只要观看网络视频,基本都会用到它. 七八 ... 
- java大牛list
			1 Java的未来 Java能干什么.不能干什么,一开始就要搞清楚.这对于成为一个纯种的Java程序猿至关重要. 2 构建Java运行环境 Java运行在服务器,服务器都是Linux系统,对于真正程序 ... 
- 分享一些免费的,开源的邮件server软件
			因为企业的须要,我们非常可能须要架设一个邮件server,微软的Exchange太复杂?GOOGLE出来的又收费!头大了吧,OK,贾芸斐在这里给大家分享推荐几个免费的开源的邮件server软件.希望你 ... 
- rsync Backups for Windows
			Transfer your Windows Backups to an rsync server over SSH rsync.net provides cloud storage for offsi ... 
- VC,一条会被鼠标移动的直线
			对话框中的小红线可以被移动的 一.类名是 CBinarizationDlg 二.定义两个变量BOOL m_flag;int nPos;在构造函数初始化m_flag = false;nPos=256;三 ... 
- Java常用代码段 - 未完待续
			记录一些自己写项目常用的代码段. 格式化常用日期格式 Date date = new Date(System.currentTimeMillis()); DateFormat d3 = DateFor ... 
- visio  ppt  axure  AI svg powerdesign xmind
			visio ppt axure AI svg powerdesign xmind 
