volatile是c++中的一个关键字。用volatile修饰的变量,具有三个性质:易变性

(一)易变性:

由于编译器对代码执行的优化,两条赋值语句,下一条语句可能会直接从上一条语句使用的寄存器中取得变量内容,通过volatile修饰变量,使得变量将被写会内存,对变量的访问也会直接从内存中读取,而不是从寄存器中获取。

测试代码1:

上述代码中,a为非volatile变量,b=a+1,对应的汇编代码为lea ecx, [eax + 1]。由于前一条语句变量a的值被保存在寄存eax中,因此b=a+1,可以直接从寄存器eax中读取值来进行计算。

测试代码2:

变量a为volatile变量,在a=fn(c)被执行后,寄存器ecx中的内容被写回到内存:mov dword ptr [esp+0Ch], ecx,在执行b=a+1时,变量a将直接从内存中进行读取,而不是使用寄存器ecx中的值。

小结:易变性。从汇编层次反应,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是直接从内存中读取。

(二)不可优化性

测试代码3:

上述代码由于编译器优化,a,b,c三个变量都是可以通过常量进行替代,最终汇编代码更加简洁。

测试代码4:

由于a,b,c变量都通过volatile修饰,在汇编层面上,编译器将不会进行优化,最终将变量直接从内存读入到寄存器。

小结:不可优化性。volatile告诉编译器,不要对该修饰变量进行优化,保证写在代码中的指令一定会被执行。

(三)顺序性

对于多线程需要被同时访问或修改的变量,为了防止并发访问修改全局变量由于编译器优化带来的问题,常常会加上volatile关键词,来防止编译器进行不必要的优化。

首先给出一个样例代码,之后再来进行讨论:

在上述样例代码中,thread1线程在执行了something赋值后,设置flag为true,然后在thread2线程中判断当前flag为true,表明当前something已经执行完毕,接下来开始执行other things。这里通过if (flag==true)来表示something已经执行完毕,实际情况是不是这样的?先看几个测试代码,再来讨论该场景。

测试代码5:

上述中A,B均为非volatile变量,在函数执行过程中,可以看到通过gcc编译器的优化,两条语句的执行顺序被交换了,即先执行了B=0,再执行了A=B+1,编译器会保证在函数结束之后最终结果没有影响,但实质上可以看出编译器可能会对函数内部指令进行优化

测试代码6:

这里将一个变量B用volatile进行修饰,但对于编译器来说,实际并没有阻止优化发生,指令依然是乱序执行的。如此:volatile变量,与非volatile变量之间的操作,是可能被编译器优化从而交互顺序执行的。实际上,从这个测试代码也可以看出最初的场景,尽管将flag声明为volatile变量,但由于编译器优化可能导致flag先于something被执行,从而导致切换到thread2线程时,flag判断为true,但并未执行something,从而导致程序逻辑混乱。

测试代码7:

从上述代码中可以看出,当两个变量都被volatile进行修饰时,编译器高度顺序执行了对应指令,并没有进行优化导致乱序执行。如此:volatile变量之间的操作,是不会被编译器交互顺序执行的

回到最初的那个场景,为了保证something和flag的执行顺序,根据测试代码7,将两个变量都通过volatile,是否可以防止乱序执行的产生?

答案是不行!尽管这样的方法可以避免编译器优化,产生出顺序执行的机器代码,但是最终机器指令是通过CPU来完成执行的,在现代CPU中,本身就已经对指令执行做了很多优化,指令乱序执行就是其提高效率的一种方法,所以将两个变量都声明为volatile,仍然不能保证CPU执行指令时是顺序执行的

一个正确的做法是:

 其实只用保证在thread1中的代码,是先于thread2中的代码执行即可。最为常用的方法,采用互斥锁机制,对执行代码进行加锁,在执行完后进行解锁

小结:顺序性。volatile变量之间的顺序性,编译器不会进行乱序优化。volatile与非volatile变量之间的顺序,编译器可能会进行优化,不保证顺序。同时,在进行多线程编程时,需要小心使用volatile,最为常用方式是通过互斥锁保证对临界区的访问。

部分内容引用自:https://www.cnblogs.com/god-of-death/p/7852394.html

C++学习之路(三):volatile关键字的更多相关文章

  1. 学习之路三十九:新手学习 - Windows API

    来到了新公司,一开始就要做个程序去获取另外一个程序里的数据,哇,挑战性很大. 经过两周的学习,终于搞定,主要还是对Windows API有了更多的了解. 文中所有的消息常量,API,结构体都整理出来了 ...

  2. Redis——学习之路三(初识redis config配置)

    我们先看看config 默认情况下系统是怎么配置的.在命令行中输入 config get *(如图) 默认情况下有61配置信息,每一个命令占两行,第一行为配置名称信息,第二行为配置的具体信息.     ...

  3. 三 volatile关键字

    一:内存模型: 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问 ...

  4. Java并发编程学习笔记 深入理解volatile关键字的作用

    引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...

  5. C语言学习笔记--const 和 volatile关键字

    1.const关键字 (1)const 修饰的变量是只读的,它不是真正的常量,本质还是变量,只是告诉编译器不能出现在赋值号左边! (2)const 修饰的局部变量在栈上分配空间 (3)const 修饰 ...

  6. 交互原型设计软件axure rp学习之路(三)

    (三)Axure rp元件的触发事件 l  OnClick(点击时): 鼠标点击事件,除了动态面板的所有的其他元件的点击时触发.比如点击按钮. l  OnMouseEnter(鼠标移入时): 鼠标进入 ...

  7. zigbee学习之路(三):按键的控制

    一.前言 通过前一次的实验,相信大家都已经对cc2530程序的编写有了一定的认识,这次我们来操作和实验的是cc2530上的按键模块. 二.原理分析 我们先来看一下按键的原理图: 根据原理图我们可以得出 ...

  8. 学习之路三十二:VS调试的简单技巧

    这段时间园子里讲了一些关于VS的快捷键以及一些配置技巧,挺好的,大家一起学习,一起进步. 这段时间重点看了一下关于VS调试技巧方面的书,在此记录一下学习的内容吧,主要还是一些比较浅显的知识. 1. 调 ...

  9. 学习之路三十五:Android和WCF通信 - 大数据压缩后传输

    最近一直在优化项目的性能,就在前几天找到了一些资料,终于有方案了,那就是压缩数据. 一丶前端和后端的压缩和解压缩流程 二丶优点和缺点 优点:①字符串的压缩率能够达到70%-80%左右 ②字符串数量更少 ...

  10. IOS7学习之路三(UISpriteKit游戏开发SKNode)

    ios7新添加了自己的游戏开发框架UISpriteKit ,可以用此做一些2D的小游戏, 今天学习了一下SKNode的知识做一下笔记,以便以后查阅. 1.SKNode继承自UIResponder. 2 ...

随机推荐

  1. EasyUI 学习笔记

    EasyUI常见错误 1 . 无论是用HMTL形式实现组件还是使用代码 + HTML 形式实现组件 , 在为组件设置属性时 , 要注意属性值的类型问题 string:必须加引号 number:不加任何 ...

  2. JDK各个版本比较 JDK5~JDK9

    JDK5 自动装箱与拆箱: 枚举 静态导入,如:import staticjava.lang.System.out 可变参数(Varargs) 内省(Introspector),主要用于操作JavaB ...

  3. 【bzoj1798】[Ahoi2009]Seq 维护序列seq 线段树

    题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...

  4. hdu 1142 A Walk Through the Forest (最短路径)

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  5. P1365 WJMZBMR打osu! / Easy

    题目背景 原 维护队列 参见P1903 题目描述 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:( 我们来简化一下这个游戏的规则 有 nnn 次点击要做,成功了就是o,失败了 ...

  6. CF527A:Playing with Paper——题解

    https://vjudge.net/problem/CodeForces-527A http://codeforces.com/problemset/problem/527/A 题目大意:一个纸长a ...

  7. 洛谷 P1640 [SCOI2010]连续攻击游戏 解题报告

    P1640 [SCOI2010]连续攻击游戏 题目描述 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备 ...

  8. 淘淘搜索结果中image属性中有多张图片的处理

    solr引擎查询某一个 商品后的结果中,image字段中如果有多张图片路径(用逗号隔开)时,前台会不 显示图片,解决方法如下: package com.taotao.portal.pojo; publ ...

  9. 题解【luoguP4053 bzojP1029 [JSOI2007]建筑抢修】

    洛谷题链 bzoj题链 PS: \(t_i\) : 在什么时候建筑 \(i\) 自爆 \(a_i\) : 修复 \(i\) 所花时间 题解 算法:贪心+堆维护 贪心策略: 直接按 \(t\) 贪心?显 ...

  10. 分割png图片

    /*** * 分割图片 */public function cut_img(){ $filename = 'site_upload/form_file_forinput/20180313/201803 ...