为什么我们使用volatile关键字?

514
可能重复:
为什么会有 volatile? 我从未使用过它,但我想知道为什么人们使用它?它到底是做什么的?我在论坛上搜索了一下,只找到了关于 C# 或 Java 的话题。

34
虽然这是一个重复的问题,但我认为Nawaz的回答比重复的问题更全面易懂。 - ross
https://dev59.com/8XVD5IYBdhLWcg3wJIAK#65641563 - alex_noname
2个回答

1489

考虑以下代码:

int some_int = 100;

while(some_int == 100)
{
   //your code
}
当这个程序被编译时,如果编译器发现程序永远不会尝试改变some_int的值,它可能会尝试通过将while循环从while(some_int == 100)优化成等价于while(true)来提高执行速度(因为while循环中的条件似乎总是为true)。(如果编译器没有对其进行优化,则必须在每次迭代中获取some_int的值并将其与100进行比较,这显然会稍微慢一些。) 然而,有时候优化(程序的某些部分)可能是不可取的,因为可能有人从程序外部更改了some_int的值,但编译器却不知道,因为它看不到;但这是您设计的方式。在这种情况下,编译器的优化会不能产生期望的结果!
因此,为确保所需的结果,您需要阻止编译器优化while循环。这就是volatile关键字发挥作用的地方。您只需要这样做:
volatile int some_int = 100; //note the 'volatile' qualifier now!
换句话说,我会这样解释: volatile 告诉编译器,"嘿编译器,我是 volatile 的,你知道吗,我可以被一些你甚至不知道的 XYZ 改变。那个 XYZ 可以是任何东西。也许是这个程序之外的某个外星人。也许是闪电、某种形式的中断、火山等等可以改变我的事物。也许。你永远不知道谁会改变我!所以,你这个无知的编译器,别再自以为是地玩全知全能的神,不要碰到我存在的代码。好吗?"
这就是如何用 volatile 防止编译器优化代码。现在在网上搜索一些示例代码吧。
引用 C++ 标准($7.1.5.1/8) 中的话:
"[...] volatile 是一个提示,告诉实现避免涉及对象的激进优化,因为对象的值可能会被实现不能检测到的手段更改[...]"
相关主题: 将结构体定义为 volatile 会使其所有成员都变成 volatile 吗?

94
需要补充的是,volatile 是一个修饰符,类似于 const (但当然具有不同的含义),因此您也可以声明只能在 volatile 实例上调用的 volatile 方法。 - ereOn
2
@Maxpm:不是,extern关键字用于其他方面。 - Nawaz
3
根据您的示例,似乎编译器在这里优化了代码,因为我猜测在 while 函数中没有更改 some_int 的值。您能否解释一下在某些情况下会更改 some_int 值的场景?如果没有,那么在这个例子中 volatile 有什么用处呢? - Vivek Kumar
4
好的回答。需要注意的是,在这个例子中,some_int的值可能会被另一个线程或中断例程更改,这是两个代码会失败的示例,仅供澄清。 (@dearvivekkumar - 这应该可以回答你的评论) - Marcelo
5
我不认为有人有时间编写样例代码来验证这个概念,因为那是一个困难的任务。请注意,缺少volatile并不能保证变量的载入被优化掉。只是当volatile存在时,它确保不会被优化掉,即使在没有关键字的情况下也很可能发生优化;区别在于缺少volatile 不能确保 这一点。 - Nawaz
显示剩余21条评论

32

在计算机编程中,尤其是在C、C++和C#编程语言中,使用volatile关键字声明的变量或对象通常具有与优化和/或线程相关的特殊属性。一般来说,volatile关键字旨在防止(伪)编译器对假定变量值不能“自行”更改的代码应用任何优化。

http://en.wikipedia.org/wiki/Volatile_variable


44
volatile与线程无关。 - BЈовић
46
volatile关键字是一个类型限定符,用于声明一个对象可以被程序中的某些东西(例如操作系统、硬件或同时执行的线程)修改。 (c) MSDN C++ Reference. (http://msdn.microsoft.com/en-us/library/12a04hfd(v=vs.80).aspx)但是,毫无疑问,MSDN和维基百科是错误的,而您是正确的。 - Ivan
17
然而,volatile 并不能帮助线程处理。与非 volatile 的读/写操作相比,volatile 读/写操作仍然可能被重新排序,这使其在线程处理方面毫无用处。此外,您可能已经注意到 MSDN 页面上的大号“Microsoft Specific”。 Microsoft 对 volatile 的实现提供了超出标准规定的额外保证。因此,严格来说,MSDN 是错误的。而维基百科错误也并不奇怪。 - jalf
14
虽然 volatile 关键字的属性与多线程有关,但在多个线程之间共享变量时使用 volatile 可能会更改程序的语义。然而,volatile 并不足以将语义更改为任何有用或明确定义的东西。 - jalf
5
很抱歉,@jalf,我害怕你不知道自己在说什么。volatile关键字确保一个线程中变量的更改在所有线程中保持一致。根据需要在该平台上插入fences、barriers、cache flushes、reloads等操作。如果您不是做PC开发,您可能了解这一点。仅因为英特尔将许多缓存管理隐藏起来并不意味着它没有发生。 - Dan
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接