什么情况下volatile的值会被改变

作者&投稿:敞美 (若有异议请与网页底部的电邮联系)
c语言什么时候用volatile~

当一个对象的值可能会在编译器的控制或检测之外被改变时,例如一个被系统时钟更新的变量,那么对象应该声明成volatile。编译器执行的某些例行优化行为不能应用在已指定为volatile的对象上。volatile限定符的用法同const非常相似,都是作为类型的附加修饰符。volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变。因此编译器不能武断的对引用这些对象的代码作优化处理。

一个对象的值可能会在编译器的控制或检测之外被改变时,例如一个被系统时钟更新的变量,那么对象应该声明成volatile。编译器执行的某些例行优化行为不能应用在已指定为volatile的对象上。volatile限定符的用法同const非常相似,都是作为类型的附加修饰符。volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变。因此编译器不能武断的对引用这些对象的代码作优化处理。

多线程的时候会改变。
程序运行到volatile定义的变量时,很显然,程序运行在当段程序中,这几乎是在说废话了。

那么,我们也许应当可以认为,如果volatile定义的变量正在我们编写的函数中,直到函数执行完毕,volatile定义的变量的值应该应该只有我们这个函数才会使之改变。也就是volatile是否被改变是受我们的函数的控制的。

问题是,这个“应当”是错的。
这是因为,函数运行的过程有可能会被打断。在现实世界中,这可能是CPU异常或是中断,导致CPU对指令的执行临时从函数跳转到操作系统的代码。

换句话说,函数有可能被打断后再被执行,打断的过程中,volatile定义的变量的值可能会被操作系统代码或是其他代码所改变。

另一个情况是,另一段代码和函数在同一时间执行。volatile定义的变量在这时候可能被另一段正在执行的代码改变值。

volatile定义的变量的使用不限于上面这2种情况。

根据这些例子,我们大致可以总结出volatile定义的变量使用的场合。

也就是楼主你说说的“变量值会被意外的改变”。

这个关键字能起到什么作用呢?它的作用就是降低变量的值可能被意外的改变的风险。但是这种降低风险并不是时时都有效的。

在不同的机器和不同的运行环境等等因素下,具体的做法都有所不同。

其中一种情况,就像huifeng00所说,强制编译器每次都从内存中读取volatile定义的变量。

需要注意的是,在有些场合,这中做法还是不能避免变量被意外改变的风险。

强制编译器每次都从内存中读取volatile定义的变量,在一些情况下可以降低变量的值可能被意外的改变的风险。

有一个具体的例子如下:

如果有一个小型系统,它每隔一段时间检查一种资源是否需要被系统回收。
假设它靠检查一个变量val来确定这一点。

val的意义,假设就是被引用数,假如被引用数是0,说明应该被系统回收。

我们可以设想,在系统的某一片刻,有2个函数在同时执行。

一个函数叫reduceRef,一个函数叫destroy。

reduceRef试图把val的值减一,表明这个资源的被引用数减了1(val被减到0后就说明资源应该被回收了)。

destroy试图指示系统,应该立即回收资源。它的具体做法是把val设置成0(这样资源会被自动回收)。

假设,在运气很糟的情况下,reduceRef和destoy的这2个操作同时进行了。

假设这个时候,val的值还是2 。

那么下面这种情况是有可能发生的。(我们把事情发生过程中的3个步骤写上编号①②③)

① val在内存中的值2被reduceRef函数读入寄存器A。
② val在内存中的值被destroy函数改为0 。
③ val的在在寄存器A中的值2被减为1 。接着1这个值被写回val在内存中的位置。
最后,val的值是1 。

我们可以看到,在这个过程中,资源本来应该在destroy函数的作用下被标记为“无条件销毁”(val被改为0),可是由于在这同时reduceRef函数发生了作用,不小心破坏了这一点,这个时候destroy函数的作用被reduceRef给破坏了。

可以说上面这个是个很傻的例子。不过这也体现出,有些值在操作过程中,应该被保护。有时候也许可以通过一些手段,通知编译器注意这一点。

(这里是val的值应该被保护,因为它不小心被reduceRef破坏了,因此reduceRef函数应该做一些修改,或许是给val变量加上volatile关键字?呵呵)

volatile关键字起的就是这种作用。

从上面这个例子也可以看出,在这种情况下,即按照huifeng00兄的建议,让对val的读取都从内存中读取,也是无济于事的。问题并不出现在这里。

在这个例子中,关键是让val的减一操作不受干扰。val受到的这种干扰就是我们所说的“变量值被意外的改变了”。

在不同的硬件上,解决方案就有不同了。

例如在有的硬件条件下,可以直接对内存中的变量进行减一操作,没必要读到寄存器中再减一。(顺便说下,我们用的个人电脑上是做不到这点的,在这种情况下计算的结果肯定是首先存储到寄存器上的。)

这种各种解决方案,如果用上了volatile关键字,那么就可以拜托编译器来处理这些工作,给编程工作提供了便利。“给编程提供便利”就是volatile存在的初衷。

不过,由于volatile关键字被现在的编译器实现的效果不怎么让人满意,一般情况下我们都靠开发平台中提供的方法来保障变量值会被意外的改变的情况,所以volatile在现实用的比较少。

这样理解,就是volatile定义的变量,的每次读取,都必须从内存中读取,不允许编译器,作优化,这里说的优化,举个例子。
假设一个变量已经把它从内存读到寄存器中了。
编译器优化后,就会直接读取寄存器中的值,而不是从内存中读取了。
因为直接读取寄存器,速度会比访问内存块,编译器优化,使得程序运行速度加快。
这个变量在多任务、中断等环境下,变量可能被其他的任务改变,属于底层的开发。
有个形象的了解就可以。

你这是单线程的程序,变量值永远不会改变。除非改写成多线程。

http://baike.baidu.com/view/608706.htm


恐龙的资料
王元青、汪筱林和李传夔发表了题为“中国东北地区中生代一滑翔的哺乳动物”的封面文章,报道了发现于内蒙古宁城地区中生代地层中的一件几乎完整的哺乳动物化石,该具化石被命名为远古翔兽(Volaticotherium antiquus gen. et sp. nov.)

安川变频器的故障有那些?
这种情况变频器有时不报任何故障,我们可以将驱动板拆下,用万用表的欧姆档检测IGBT的门机触发极给定端,检查各个端的电阻是平衡,如果出现100Ω 以上的差别,说明触发电路已经有元件损坏。需要更换驱动板。3) IGBT,保险 IGBT烧坏后变频器会报PUF故障。IGBT和保险的烧坏过程为下,大电流的产生导致IGBT被击穿,IGBT击穿时...

谁介绍几部好看的电影,科幻的。
“威震天”召来了新帮手大力神,“汽车人”阵容则出现“声波”和女金刚“阿尔茜”与,正反阵容有10位左右新老金刚将逐一登场,一决高下。 2.<Crank2 High Volatage 怒火攻心2:高压电> 2006年那部让各位男性热血沸腾的动作片《怒火攻心》推出续集《怒火攻心2:高压电》,杰森·斯坦森饰演的查夫·查利尔斯这一次比第...

09年最新电影
《星际迷航》最早播出于1973年那时它只一部讲述星际旅行时空科幻动画剧集播出后却大受欢迎几十年来人们拍出了许多续集以及各种版本时至今日仍旧念念不忘本片讲述詹姆斯·寇克和斯宝克早期生活包括们第一次舰队学院相遇以及第一次完成外太空任务情况 9.<Iceage3 冰河世纪3:恐龙的黎明> 为了坚果不要命的小松鼠将把我...

曲阳县15693352061: 什么情况下volatile的值会被改变 -
年姣抗感: 多线程的时候会改变. 程序运行到volatile定义的变量时,很显然,程序运行在当段程序中,这几乎是在说废话了.那么,我们也许应当可以认为,如果volatile定义的变量正在我们编写的函数中,直到函数执行完毕,volatile定义的变量的值应该...

曲阳县15693352061: java中volatile的关键字什么情况下能用 -
年姣抗感: 一般用在多线程情况下,某成员变量会被另一线程改变.

曲阳县15693352061: C语言中volatile在什么情况下使用 -
年姣抗感: volatile是易变的,不稳定的意思,volatile是关键字,是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等,遇到这个关键字声明的变量,编译器对访问该变量的代码不在进行优化,从而可以提供对特殊地址的稳定访问. volatile 关键字告诉编译器该变量是随时可能发生变化的,每次使用它的时候必须从内存中取出他的值,因而编译器生成的汇编代码会从原内存地址中读取数据使用.如果一个寄存器或者变量表示一个端口或者多个线程的共享数据,就容易出错,所以volatile可以保证对特殊地址的稳定访问.

曲阳县15693352061: 关于c语言中的volatile限定符 -
年姣抗感: 当一个对象的值可能会在编译器的控制或检测之外被改变时,例如一个被系统时钟更新的变量,那么对象应该声明成volatile.编译器执行的某些例行优化行为不能应用在已指定为volatile的对象上.volatile限定符的用法同const非常相似,都是作为类型的附加修饰符.volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变.因此编译器不能武断的对引用这些对象的代码作优化处理.

曲阳县15693352061: const 和 volatile 在C语言中有何区别 const定义的值不能被修改 volatile定义的值也不能被修改 两者用法有 -
年姣抗感: const定义的值不能被修改 volatile可以 volatile的意思是它定义的变量很可能被修改 程序每次读这个变量时不是从寄存器读而是从内存读 防止该值发生了改变

曲阳县15693352061: java volatile在什么场景下适用 -
年姣抗感: JVM有两种运行模式Server与Client.两种模式的区别在于,Client模式启动速度较快,Server模式启动较慢;但是启动进入稳定期长期运行之后Server模式的程序运行速度比Client要快很多.这是因为Server模式启动的 JVM采用的是重量级的虚...

曲阳县15693352061: C语言中关键字volatile是什么意思 -
年姣抗感: volatile的本意是一般有两种说法.1.“暂态的 2.“易变的.这两种说法都有可行.一个定义为volatile的变量是说这变量可能会被意想不到的改变,这样,编译器就不会去假设这个变量的值了.优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份. www.okeycar.com

曲阳县15693352061: C中关键字volatile的意思,主要作用是什么?(通俗易懂的),谢谢. -
年姣抗感: 简单的理解就是这个变量可能会被外部函数改变,为了让这个改变能有效执行,不被编译器优化掉.举个例子吧,一个函数用了一个外部的变量,但这个变量在此函数中没有改变,只是引用,这时候编译器会去做优化,把它的值暂放在内部寄存器中,用的时候读取的是寄存器的值,而不是去访问它的地址取值,这样的话,当这个变量在外部发生了变化的时候,比如中断,或者另外的进程等等.但在这个函数里面就不能起作用,因为被优化后使用的是寄存器的值,还是原来的值,导致错误发生.这种情况下,就要加上这个定义,就不会被优化了.

曲阳县15693352061: c 语言中关于 volatile 形参问题?? -
年姣抗感: 会的,因为加上volatile限定符就表示他可能会被意外改变,优化器每次都会直接读他的值

曲阳县15693352061: 多线程编程中什么情况下需要加 volatile -
年姣抗感: 来看这个代码:int fun(int& a) { int b = a; int c = a; return a+b+c; } int main() { int a=1; //.........做一些和a无关的事 return fun(a); } 这个代码是很好优化的,因为编译器知道a的值是1,参考上下文,编译器又能知道b和c的值也是1,而且根本没有人...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网