【问题标题】:C++: Reordering atomic store (release) and load (acquire)C++:重新排序原子存储(发布)和加载(获取)
【发布时间】:2018-02-25 13:52:17
【问题描述】:

我编写了以下代码,它的作用有点像一个写入器和一个读取器的同步队列。永远不会超过 1 位读者和 1 位作者。

作者反复调用设计为无锁的maybePublish。相反,读者使用spinUntilFreshAndFetch。它通过原子变量通知它想要下一个非常新鲜的项目。存储后,它在原子变量上旋转,等待写入者将其设置回 0,之后它可以获取共享对象并将其放入自己的副本中。

class Shared {
public:
    void maybePublish(const Item &item) {
        if (mItemSync.load(std::memory_order_acquire) == 1) {
            mItem = item;
            mItemSync.store(0, std::memory_order_release);
        }
    }

    void spinUntilFreshAndFetch(Item *copy) {
        mItemSync.store(1, std::memory_order_release);  // A
        while (mItemSync.load(std::memory_order_acquire) != 0) {  // B
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }
        *copy = mItem;
    }
private:
    Item mItem;
    std::atomic_int32_t mItemSync = 0;
};

我担心的是 A 行和 B 行。我在标准中看不到任何不允许交换这些行的内容。该标准保证发布不会浮动在获取之上,但并不保证获取不能浮动在发布之上。

另外,我担心它可能会被优化。例如,编译器是否可以假设在 B 处,mItemSync 只能是 1(来自 A 行),并将其变成无限循环?

根据我看到的教程,如果我改用std::memory_order_seq_cst,则无法重新排序 A 和 B。我应该这样做吗?

感谢您的建议!

【问题讨论】:

  • 加载顺序在存储之后,并会观察此存储的结果。即使对于普通的非原子变量也是如此——这两个操作都由同一个线程执行。
  • 谢谢!这对我来说很有意义。但是,作者可以观察到由于这里的重新排序而产生的任何奇怪的效果吗?而且大概,编译器不能做那个无限循环优化?
  • 编译器不能优化掉原子操作,它必须假设一个原子可以随时改变它的值,通过当前线程之外的一些动作;这就是原子的意义所在。我不确定你所说的“奇怪的影响”是什么意思。对于它的价值,我没有立即发现您的代码有任何问题,但我不会远程称自己为专家。

标签: c++ atomic


【解决方案1】:

程序没问题。

原子意味着:编译器不能在单个线程上重新排序它们,保证波动性(因此没有无限循环)和原子性(操作是不可分割的)。

获取和释放语义意味着:如果获取操作观察到释放操作的副作用,无论释放完成之前是什么。

如果我们将发布表示为},并将获取表示为{。括号内的任何内容都不能根据其语义向外移动。然后你的两个线程看起来像

reader             } {  {  {{   {   { R
writer {    {   {{    {  W       }
                   ^  ^          ^  ^
                   1  2          3  4
  1. 作者首先反复尝试发布和获取,直到读者发布才会失败。

  2. 作者将在读者发布后的某个时间获取。

  3. 同时读取器反复尝试获取,直到写入器释放时才会失败。

  4. 读者获得。

请注意这 4 个操作必须按此顺序发生。写入mItem 保证在23 之间,读取必须在4 之后发生。结合平铺这两个线程仍然保留此属性意味着程序很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 2018-11-28
    • 1970-01-01
    相关资源
    最近更新 更多