【问题标题】:Using volatile boolean variable for busy waiting使用 volatile 布尔变量进行忙碌等待
【发布时间】:2013-11-24 20:27:40
【问题描述】:

在阅读了其他开发人员编写的一些代码后出现了这个问题,所以我做了一些研究,发现了 Andrei Alexandrescu 的文章。在他的article 中,他说可以使用 volatile 布尔变量来忙等待(请参阅第一个带有 Wait/Wakeup 的示例)

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

我真的不明白它是如何工作的。

  1. volatile 不保证操作是原子的。实际上,对布尔变量的读/写是原子的,但理论并不能保证这一点。在我看来,上面的代码可以使用 C++11 安全地重写,方法是使用 std::atomic::load/store 函数和相应的获取/释放内存排序约束。
  2. 我们在所描述的示例中没有这个问题,但是如果我们有不止一次写入,我们可能会遇到内存排序问题。 Volatile 不是栅栏,它不强制内存排序,它只是阻止编译器优化。

那么为什么这么多人使用 volatile bool 来忙等待,它真的便携吗?

【问题讨论】:

  • 我不是这方面的权威,但我的直觉和你一样。此外,可能值得注意的是,您的代码中没有 volatile bools ;)也可能文章可以追溯到 2001 年 2 月 1 日。
  • Possible answer 关于几乎重复的问题。
  • 是的,你是对的。我从第一个示例中复制了源代码,他稍后添加了 volatile。让我解决这个问题。
  • @Lightness Races in Orbit:感谢您的链接,看起来很有趣。我现在去看看。

标签: c++ multithreading volatile memory-fences busy-waiting


【解决方案1】:

文章并没有说volatile 是你所需要的(事实上,它不是),只是说它可能有用。

如果你这样做,如果你使用简单的泛型组件LockingPtr,你可以编写线程安全的代码,而不必担心竞争条件,因为编译器会为你和会努力指出你错的地方。

【讨论】:

  • 如果是这样那就很清楚了,但是我在谈论这部分 Most explanations of the rationale and usage of volatile stop here and advise you to volatile-qualify the primitive types that you use in multiple threads. However, there is much more you can do with volatile, because it is part of C++'s wonderful type system. 他并没有说建议将 volatile 用于多个线程中使用的原始类型的人是错误的,因为实际上 volatile 有与 C++ 中的多线程无关。
  • @axe:好吧,那怎么样? volatile 类型系统的一部分,所以你可以根据它来选择重载。在多线程应用程序的可能设计中,您必须将其视为一个工具
  • 你从哪里弄来的? :)
  • @axe:我从哪里拿来的东西?
  • 我的意思是你抄了那句话?我以为是从文章中找到的,但在那里找不到。
【解决方案2】:

我真的不明白它是如何工作的。

它依赖于两个假设:

  • 对布尔变量的读写是原子的;
  • 所有线程都有统一的内存视图,因此在一个线程上所做的修改将在短时间内对其他线程可见,而无需显式内存屏障。

第一个可能适用于任何健全的架构。第二种适用于任何单核架构,也适用于当今广泛使用的多核架构,但不能保证它会在未来继续存在。

上面的代码可以使用std::atomic安全地用C++11重写

今天,它可以而且应该是。 2001年写这篇文章的时候,没那么多。

如果我们有超过一个写入,我们可能会遇到内存排序问题

确实如此。如果此机制用于与其他数据同步,那么我们依赖第三个假设:保留修改顺序。同样,大多数流行的处理器都会提供这种行为,但不能保证这种行为会继续下去。

为什么这么多人使用 volatile bool 来忙等待

因为他们不能或不会改变在 C++ 获得多线程内存模型之前形成的习惯。

它真的便携吗?

没有。 C++11 内存模型不能保证这些假设中的任何一个,而且随着典型内核数量的增长,它们很有可能对于未来的硬件支持变得不切实际。 volatile 从来都不是线程同步的解决方案,而且现在该语言确实提供了正确的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    相关资源
    最近更新 更多