为什么我们在C++中使用volatile关键字?

Naw*_*waz 347 c++ volatile compiler-optimization

可能重复:
C++:什么时候有挥发性关键字帮你?

我从来没有用过它,但我想知道为什么人们会用它?它到底是做什么的?我搜索了论坛,发现它只是C#或Java主题.

Naw*_*waz 1065

考虑一下这段代码

int some_int = 100;

while(some_int == 100)
{
   //your code
}
Run Code Online (Sandbox Code Playgroud)

当编译该程序时,编译器可以优化此代码,如果它发现程序永远不会尝试更改其值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!
Run Code Online (Sandbox Code Playgroud)

换句话说,我会解释如下:

volatile 告诉编译器,

"嘿编译器,我很不稳定,你知道,我可以通过一些你甚至都不知道的XYZ来改变.那个XYZ可能是任何东西.也许这个星球外的一些外星人称为程序.也许有些照明,某种形式中断,火山等等可以让我变异.也许.你永远不知道谁会改变我!所以你无知,不要再扮演一个全知的神,也不敢触摸我在场的代码.好的?"

好吧,这就是volatile阻止编译器优化代码的方法.现在搜索网络以查看一些示例示例.


引用C++标准($ 7.1.5.1/8)

[..] volatile是对实现的暗示,以避免涉及对象的激进优化, 因为对象的值可能会被实现无法检测到的更改.[...]

相关主题:

使结构变为volatile会使其所有成员变得不稳定吗?

  • 重要的是要添加`volatile`是一个限定符,类似于`const`(但当然具有不同的含义),所以你也可以声明只能在`volatile`实例上调用的`volatile`方法. (61认同)
  • 根据您的示例,编译器似乎在这里很好地优化了代码,因为我猜在 while 函数内部它没有改变 some_int 的值。您还可以解释 some_int 值发生变化的任何情况吗?如果不是,那么在这个例子中 volatile 的用途是什么? (3认同)
  • 很好的答案,最好提到在示例中,some_int 的值可以被另一个线程或中断例程更改,作为代码将失败的两个示例,只是为了澄清。(@dearvivekkumar - 这应该回答你的评论) (3认同)
  • @Maxpm:不。`extern`关键字用于其他内容。 (2认同)
  • @ user180574:我认为没有人有时间提出示例代码来验证此概念,因为这是一项艰巨的任务。注意,“ volatile”的“不存在”并不能保证变量的“ loading”将被优化。仅仅存在volatile的*存在*可以确保**没有被优化,即使没有关键词也很有可能。不同之处在于*缺席*不能保证**。 (2认同)
  • @patzi 是的,一个程序可以访问另一个程序的内存。一个例子是操作系统可以访问它想要的任何内存,无论它是否属于它。另一个例子是访问共享缓冲区的两个程序,例如由 mmap 创建。 (2认同)

Iva*_*van 17

在计算机编程中,特别是在C,C++和C#编程语言中,使用volatile关键字声明的变量或对象通常具有与优化和/或线程相关的特殊属性.一般来说,该volatile关键字旨在防止(伪)编译器对代码应用任何优化,这些优化假设变量值不能"自行更改".(c)维基百科

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

  • volatile与线程无关 (34认同)
  • volatile关键字是一个类型限定符,用于声明可以通过诸如操作系统,硬件或同时执行的线程之类的东西在程序中修改对象.(c)MSDN C++参考.(http://msdn.microsoft.com/en-us/library/12a04hfd(v=vs.80).aspx)但是msdn和维基百科肯定是错的,你是对的. (32认同)
  • 虽然`volatile`的属性与*threading相关,但确实如此.对线程之间共享的变量使用`volatile`可以改变程序的语义.`volatile`只是不够强大,不能将语义改为任何有用*或定义明确的东西. (10认同)
  • 但是`volatile`对线程没有帮助.对于非易失性读/写,仍然可以对易失性读/写进行重新排序,这使得它对于线程目的而言是无用的.此外,您可能已经注意到MSDN页面上的大胖"Microsoft Specific".Microsoft的volatile实现提供了超出标准规定的额外保证.所以是的,从技术上讲,MSDN是错误的.维基百科错误应该不足为奇. (8认同)
  • @curiousguy 这是一个 C++ 问题,我的评论是关于 Java 和 C#(一旦表明我对 C++ 的看法是错误的),所以我们不应该污染这个线程。无论如何:对于 Java,请阅读 [this](https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html) 和 [this](https://docs.oracle.com/javase/specs) /jls/se7/html/jls-17.html)这是一个经典示例:/sf/ask/811710791/ Different-线 。对于 C#,请使用 Google ;-) (3认同)
  • 恐怕您不知道您在说什么@jalf。在一个线程中更改为变量的volatile关键字被授予者,在所有线程中保持一致。通过插入该平台所需的围栏,屏障,缓存刷新,重新加载等。如果您除了PC开发之外还做其他任何事情,您可能都知道。仅仅因为intel对您隐藏了很多缓存管理并不意味着它没有发生。 (2认同)
  • 在Java中,[`volatile实际上与线程有关](https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html),我相信它在C ++和C#中具有相似的含义。 (2认同)
  • @jjmontes 事实上,在Java中,“易失性”是线程的通信工具,对这些标量的写入具有特定的含义。**在 C 和 C++ 中,“易失性”主要是用于 MMIO**(扩展卡、驱动程序...)、异步信号、特殊伪函数“setjmp”的工具,并且具有与线程无关的其他用途。C 和 C++ 中线程间通信的标准支持是通过原子对象(C++ 中拼写为“std::atomic<T>”)。它们的语义完全不同。 (2认同)