【问题标题】:Usefulness of volatile in concurrent programming since C++11从 C++11 开始,volatile 在并发编程中的用处
【发布时间】:2018-07-29 01:21:50
【问题描述】:

我已阅读 thisthis 的答案。我还搜索了C++ Concurrency in Action 这本书,发现没有关于volatile 的讨论,也没有任何使用它的示例。看起来它根本不是为并发而设计的。那么对于并发编程,只使用 atomic、mutex 等就足够了,而忘记了volatile?并发问题可能需要volatile 的任何情况?

【问题讨论】:

  • 不,没有—— volatile 更多地是为处理内存映射硬件寄存器等事情而设计的。对于并发编程,它根本不是适合这项工作的工具。
  • 没有提到它是有原因的,这与没有提到海盗船和香蕉和维特根斯坦的 Tractatus 的原因是一样的。
  • @nolbdnilo Arrrr!
  • 这个问题已经在 SO 上被问及回答了很多。问题是,一些竖起大拇指的绿色复选标记答案是错误的。简短的回答是,如果您没有与内存映射硬件接口,请忘记您曾经听说过volatile。你不记得你知道的不会伤害你。

标签: c++ c++11 concurrency volatile


【解决方案1】:

不,在 C++ 中,volatile 关键字告诉编译器不得以任何方式优化变量的形状或形式。这在处理可以从您自己的代码外部更改的内存时非常有用,例如自定义板上的硬件寄存器。
有关 volatile 的更深入指南,您应该阅读 Volatile vs. volatile By Herb Sutter

【讨论】:

    【解决方案2】:

    volatileatomic 是两个正交的概念。所以它们的组合改变了程序语义,否则它们就不是正交的!

    原子性 对排序造成限制(包括读写的原子性)。

    波动性会限制对变量的访问的可省略性。

    volatile 不会导致线程之间的任何排序,但它仍然有用。考虑这个程序,它显示一个进度条,计算在一个线程中执行,而另一个线程负责图形:

    //thread A
    extern std::atomic<int> progress;
    //
    void compute(){
      progress=0;
      //do something;
      progress=1;
      //do something;
      progress=2;
      //[...] a 100 time.
      }
    

    在函数compute 中,编译器注意到progress 从未被读取,而是被多次写入。因此它可以将代码优化为:

    void compute(){
      //do many thing;
      progress=100;
      }
    

    通过声明volatile atomic&lt;int&gt; progress;,所有写入都不会被折叠,并且内存顺序将确保在所有这些写入之间执行操作。

    另见:

    【讨论】:

    • 我很确定这是不正确的。 Volatile 绝对没有任何内存顺序承诺。原子确实。我听到的每一位语言律师都对此表示赞同,包括 Right Hon。 Bjarne Stoustrup,曾说过不要将volatile 用于任何高于硅和火花的东西,没有例外。
    • 废话:编译器无法优化对原子对象的访问,除非它可以证明没有其他线程可能访问这些值。
    • @JiveDadson 不幸的是,应该和必要之间总是存在差距。
    • @DietmarKühl 试着证明你在这个case 中所说的话。在这种情况下,优化器有权将所有写入合并到进度。
    • @DietmarKühl 实现应该使原子存储在合理的时间内对原子负载可见。你认为这句话是什么意思?您是否相信每次他们是商店时都会发生负载?如果在该商店或随后对该商店执行的商店上执行加载,则该商店是可见的!
    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 2011-09-26
    • 2011-01-11
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多