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. Go语言【第九篇】:Go数据结构之:数组

    Go语言数组 Go语言提供了数组类型的数据结构.数组时具有相同唯一类型的一组已编号且长度固定的数据项序列,中类型可以是任意的原始类型如整形.字符串或者自定义类型. 相对于声明number0,numbe ...

  2. RESTful Webservice

    1,REST和RESTFUL是什么? REST ( REpresentational State Transfer ),State Transfer 为 "状态传输" 或 &quo ...

  3. 【刷题】BZOJ 1002 [FJOI2007]轮状病毒

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子 和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下 ...

  4. [牛客练习赛29D]禁止动规

    description newcoder 你在一个无限长的数轴上,一开始你在原点 本来你只有两种操作:向左dp,以及向右dp 然而由于禁止dp 于是你只能另寻出路 万幸的是,dp之神随机给了你n个变量 ...

  5. 【Codeforces Round #404 (Div. 2)】题解

    A. Anton and Polyhedrons 直接统计+答案就可以了. #include<cstdio> #include<cstring> #include<alg ...

  6. bzoj 3280: 小R的烦恼 (网络流)

    和开发计划一样(数组开太小wa了好多次,然后为什么这么慢? type arr=record toward,next,cap,cost:longint; end; const maxm=; maxn=; ...

  7. [NOIP2017]逛公园 最短路图 拓扑序DP

    ---题面--- 题解: 挺好的一道题. 首先我们将所有边反向,跑出n到每个点的最短路,然后f[i][j]表示从i号节点出发,路径长比最短路大j的方案数. 观察到,如果图中出现了0环,那么我们可以通过 ...

  8. RobHess的SIFT源码分析:imgfeatures.h和imgfeatures.c文件

    SIFT源码分析系列文章的索引在这里:RobHess的SIFT源码分析:综述 imgfeatures.h中有SIFT特征点结构struct feature的定义,除此之外还有一些特征点的导入导出以及特 ...

  9. crontab使用进程锁解决冲突

    想到一个问题,如果在crontab里有个定时任务设置为一分钟执行一次,但是它执行的时间可能会超过一分钟,此时crontab一分钟后会再次运行该脚本吗?这样会不会出现冲突呢?网上找了下,说可以用Linu ...

  10. android xml字符串通配

    1.基本使用方法 xml中定义如下字符串: <string name="buff">%1$d --- %2$s</string> 代码中解析: String ...