C++学习之路(三):volatile关键字
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关键字的更多相关文章
- 学习之路三十九:新手学习 - Windows API
来到了新公司,一开始就要做个程序去获取另外一个程序里的数据,哇,挑战性很大. 经过两周的学习,终于搞定,主要还是对Windows API有了更多的了解. 文中所有的消息常量,API,结构体都整理出来了 ...
- Redis——学习之路三(初识redis config配置)
我们先看看config 默认情况下系统是怎么配置的.在命令行中输入 config get *(如图) 默认情况下有61配置信息,每一个命令占两行,第一行为配置名称信息,第二行为配置的具体信息. ...
- 三 volatile关键字
一:内存模型: 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问 ...
- Java并发编程学习笔记 深入理解volatile关键字的作用
引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...
- C语言学习笔记--const 和 volatile关键字
1.const关键字 (1)const 修饰的变量是只读的,它不是真正的常量,本质还是变量,只是告诉编译器不能出现在赋值号左边! (2)const 修饰的局部变量在栈上分配空间 (3)const 修饰 ...
- 交互原型设计软件axure rp学习之路(三)
(三)Axure rp元件的触发事件 l OnClick(点击时): 鼠标点击事件,除了动态面板的所有的其他元件的点击时触发.比如点击按钮. l OnMouseEnter(鼠标移入时): 鼠标进入 ...
- zigbee学习之路(三):按键的控制
一.前言 通过前一次的实验,相信大家都已经对cc2530程序的编写有了一定的认识,这次我们来操作和实验的是cc2530上的按键模块. 二.原理分析 我们先来看一下按键的原理图: 根据原理图我们可以得出 ...
- 学习之路三十二:VS调试的简单技巧
这段时间园子里讲了一些关于VS的快捷键以及一些配置技巧,挺好的,大家一起学习,一起进步. 这段时间重点看了一下关于VS调试技巧方面的书,在此记录一下学习的内容吧,主要还是一些比较浅显的知识. 1. 调 ...
- 学习之路三十五:Android和WCF通信 - 大数据压缩后传输
最近一直在优化项目的性能,就在前几天找到了一些资料,终于有方案了,那就是压缩数据. 一丶前端和后端的压缩和解压缩流程 二丶优点和缺点 优点:①字符串的压缩率能够达到70%-80%左右 ②字符串数量更少 ...
- IOS7学习之路三(UISpriteKit游戏开发SKNode)
ios7新添加了自己的游戏开发框架UISpriteKit ,可以用此做一些2D的小游戏, 今天学习了一下SKNode的知识做一下笔记,以便以后查阅. 1.SKNode继承自UIResponder. 2 ...
随机推荐
- 第24天:js-函数变量声明提升
一.函数声明1.自定义函数function fun1(){ alert("我是自定义函数");}fun2();//函数不调用,自己不执行2.直接量声明var fun2=functi ...
- 复杂类型的write写入功能 步骤解析
- zoj3209-Treasure Map
给出一个左下角为\((0,0)\),右上角为\((n,m)\)的矩形,再给出\(k\)个在大矩形内的小矩形(可以重合),问是否能用这些小矩形完全覆盖这个大矩形,并且没有重合,如果可以至少需要多少个. ...
- BZOJ4754 JSOI2016独特的树叶(哈希)
判断两棵无根树是否同构只需要把重心提作根哈希即可.由于只添加了一个叶子,重心的位置几乎不发生偏移,所以直接把两棵树的重心提起来,逐层找哈希值不同且对应的两子树即可.被一个普及组子问题卡一年. #inc ...
- [洛谷P4735]最大异或和
题目大意:有一串初始长度为$n$的序列$a$,有两种操作: $A\;x:$在序列末尾加一个数$x$ $Q\;l\;r\;x:$找一个位置$p$,满足$l\leqslant p\leqslant r$, ...
- Android APP性能优化(最新总结)
导语 安卓大军浩浩荡荡,发展已近十个年头,技术优化日异月新,如今Android 8.0 Oreo 都发布了,Android系统性能已经非常流畅了.但是,到了各大厂商手里,改源码自定系统,使得And ...
- POJ3422:Kaka's Matrix Travels——题解
http://poj.org/problem?id=3422 题目大意: 从左上角走到右下角,中途取数(数>=0),然后该点的数变为0,求走k的总价值和最大值. ———————————————— ...
- POJ3498:March of the Penguins——题解
最近的题解的故事背景割. 题目: 描述 在靠近南极的某处,一些企鹅站在许多漂浮的冰块上.由于企鹅是群居动物,所以它们想要聚集到一起,在同一个冰块上.企鹅们不想把自己的身体弄湿,所以它们在冰块之间跳跃, ...
- IP协议简介
一.IP 1.IP是TCP/IP协议簇中最为核心的协议,所有的TCP.UDP.ICMP及IGMP数据都是以IP数据报格式传输. 2.IP提供不可靠.无连接的数据报传送服务 (1)不可靠:不保证IP数据 ...
- UVA.674 Coin Change (DP 完全背包)
UVA.674 Coin Change (DP) 题意分析 有5种硬币, 面值分别为1.5.10.25.50,现在给出金额,问可以用多少种方式组成该面值. 每种硬币的数量是无限的.典型完全背包. 状态 ...