【问题标题】:Is volatile int in C as good as std::atomic<int> of C++0x?C 中的 volatile int 是否与 C++0x 的 std::atomic<int> 一样好?
【发布时间】:2011-10-01 10:32:27
【问题描述】:

我的程序中需要有原子变量。以前我用的是std::atomic&lt;int&gt;,但是我现在工作的平台没有支持C++0x的g++编译器。我使用了volatile int,它似乎可以正常工作,因为我在测试它的多核系统中还没有经历过竞争条件。

我的问题是volatile int 是否像std::atomic&lt;int&gt; 一样原子?此外,它是否会创建内存屏障(我也需要)?

【问题讨论】:

  • 如果是,他们为什么要添加atomic&lt;&gt;? ;) 通常的经验法则适用,语言设计者并非完全疯了,所以他们这样做可能有一些原因:)
  • 那么解决办法是什么?有什么想法吗?
  • “解决方案”?你问了什么基本上是一个是/否的问题。答案是“不”(原因是,正如我所说,“如果他们确实做了同样的事情,就没有理由添加atomic)。但是没有您的问题中有问题陈述,因此没有“解决方案”的空间。您是否正在寻找类似“不,volatile 不适合这里,所以您需要使用std::atomic,或者使用适当的记忆障碍”?如果是这样,那么这就是你的答案。:)

标签: c c++11 atomic volatile


【解决方案1】:

没有。 volatile 与多线程无关。它不强制执行内存屏障(尽管某些编译器可能会选择添加它无论如何),并且它不保证关于非易失性对象的读/写重新排序。

volatile 被添加以支持写入内存映射的硬件 I/O 寄存器,在这种情况下,重要的是您的写入没有被优化掉,但没有精确的顺序保证 wrt。需要非易失性读/写。

您可能还想阅读this

【讨论】:

  • std::atomic 是否对非原子访问施加了排序要求?
  • 一个volatile变量的值可以在未经程序同意的情况下改变,所以编译器不应该在优化策略中使用它。
  • @Ben:是的,据我所知,它本质上是被内存屏障包围的
  • @jalf:由于写入 volatile 是“可观察的”,它不会给你一些排序保护吗?也就是说,如果我使用可能具有副作用的表达式写信给 volatile1,然后写信给 volatile2,我会认为“可观察”行为保证会授予订单。
  • 请注意,对于 MSVC volatile 确实 意味着内存屏障,并且无法选择退出此行为。
【解决方案2】:

易失性变量并不意味着内存屏障,也没有std::atomicexchangecompare_exchange_* 操作。它们确实避免了编译器在机器代码级别将负载提升为多个负载(反之亦然,商店类似),仅此而已。

您可能对这些文章感兴趣:

如果您没有std::atomic,您可能想要使用boost::atomic,或者使用您正在使用的任何编译器提供的低级屏障和原子操作原语。

【讨论】:

【解决方案3】:

我看到你在一些 cmets 中询问 GCC,给你。

GCC's Built-in functions for atomic memory access

【讨论】:

    【解决方案4】:

    在 C++0x 之前,该语言不支持线程感知,因此它不会阻止多重访问。将其声明为 volatile 会有所帮助,但不会阻止比赛。

    更多详情请见http://en.wikipedia.org/wiki/Volatile_variable

    要真正实现原子操作,您需要使用线程库(win32 线程、pthread 等)提供的任何锁定机制。

    【讨论】:

      【解决方案5】:

      Herb Sutter 对 here 的差异进行了很好的总结。总结(剪切和粘贴):

      为了安全地编写无锁代码, 在没有线程之间进行通信 使用锁,更喜欢使用有序 原子变量:Java/.NET volatile, C++0x 原子,与 C 兼容 原子_T。

      为了安全地与特殊人员沟通 硬件或其他内存 不寻常的语义,使用不可优化 变量:ISO C/C++ 易失性。 请记住,读取和写入 这些变量不一定 然而,原子的。

      【讨论】:

      • 使用 atomic_t 时要包含哪个头文件?
      • @MetallicPriest:GCC 中没有 atomic_t。这是一个 VC++ 扩展。
      • @Steve, @MetallicPriest:对不起,我正在寻找一个实际的 atomic_t 关键字。 GCC 在&lt;stdatomic.h&gt; (C) 或&lt;cstdatomic&gt; (C++) 中有原子类型。
      • 为 C1x 提出了一个 _Atomic 限定符。我认为目前还没有人支持它。 C++0x 和 C1y 确实在原子和线程模型上协同工作,因此它们最大限度地提高了兼容性。
      • 在某些 gcc 版本中 stdatomic.h 不存在。
      【解决方案6】:

      volatile 基本上告诉编译器它不能对特定内存位置中的内容做出假设。比如

      bool test = true;
      while(!test)
      {
          /* do something (e.g. wait) */
      }
      

      编译器可能会优化掉整个while,因为它假定test 始终为真。然而,如果test 将在某个时候从其他地方(例如某些硬件或另一个线程)更新,我们不希望编译器假设它知道test 中的内容。我们可以告诉编译器使用volatile

      正如其他答案所说,它不能保证事物访问内存位置的顺序。

      附:我无耻地从某个地方偷了那个例子,但不记得我在哪里看到的。

      【讨论】:

      • 我意识到我完全搞砸了那个例子,我希望 volatile 的功能从我所说的仍然有意义。我将尝试寻找示例的原始来源并将其发布在此处。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2012-03-22
      • 2011-06-19
      • 2011-02-20
      • 2020-07-18
      • 2017-03-15
      • 2013-12-19
      相关资源
      最近更新 更多