简体   繁体   English

C ++:重新排序原子库(发布)和加载(获取)

[英]C++: Reordering atomic store (release) and load (acquire)

I have written the following code, which acts a bit like a synchronous queue for one writer and one reader. 我编写了以下代码,它有点像一个编写器和一个阅读器的同步队列。 Never more than 1 reader and 1 writer. 从不超过1位读者和1位作家。

The writer repeatedly calls maybePublish which is designed to be lock-free. 作者反复调用maybePublish ,它被设计为无锁。 The reader, instead, uses spinUntilFreshAndFetch . 相反,读者使用spinUntilFreshAndFetch It notifies through the atomic variable that it wants the next, very fresh item. 它通过原子变量通知它想要下一个非常新鲜的项目。 After storing, it spins on the atomic variable, waiting for the writer to set it back to 0, after which it can take the shared object and place it into its own copy. 存储之后,它会旋转原子变量,等待编写器将其设置回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;
};

My worry is about line A and B. I can't see anything in the standard that wouldn't allow these lines to be swapped. 我的担心是关于A行和B行。我在标准中看不到任何不允许交换这些行的内容。 The standard guarantees a release won't float above an acquire, but not that an acquire can't float above a release. 该标准保证发行不会浮动在收购之上,但并不意味着收购不能浮动在发行之上。

Also, I worry that it might be otherwise optimized. 另外,我担心它可能会被优化。 For example, could the compiler assume that, at B, mItemSync cannot be anything else but 1 (from line A), and turn this into an infinite loop? 例如,编译器是否可以假设,在B处, mItemSync除了1(来自A行) mItemSync不能是其他任何东西,并将其转换为无限循环?

According to a tutorial I saw, A and B cannot be reordered if I use std::memory_order_seq_cst instead. 根据我看到的教程,如果我使用std::memory_order_seq_cst而不能重新排序A和B. Should I do this? 我应该这样做吗?

Thanks for any advice! 谢谢你的建议!

The program is fine as is. 该计划很好。

Atomics means: the compiler cannot reorder them around on a single thread, guarantees volatility (hence no infinite loops) and atomicity (operations are inseperable). 原子意味着:编译器不能在单个线程上重新排序它们,保证波动性(因此没有无限循环)和原子性(操作是不可分割的)。

Acquire and release semantics means: if an acquire operation observes a side effect from a release operation, whatever is before the release is completed. 获取和释放语义意味着: 如果获取操作观察到释放操作的副作用,则在发布之前完成任何操作。

If we were to denote release as } and acquire as { . 如果我们将释放表示为}并获得为{ Anything within brackets cannot move outwards as per their semantics. 括号内的任何内容都不能按其语义向外移动。 Your two threads would then look like 你的两个线程看起来就像

reader             } {  {  {{   {   { R
writer {    {   {{    {  W       }
                   ^  ^          ^  ^
                   1  2          3  4
  1. The writer first repeatedly tries to publish and acquire, which will fail until the reader releases. 作者首先反复尝试发布和获取,直到读者发布才会失败。

  2. The writer will acquire sometime after the reader releases. 作者将在读者发布后的某个时间获得。

  3. Meanwhile the reader repeatedly tries to acquire, which will also fail until the writer releases. 与此同时,读者反复尝试获取,在作者发布之前也会失败。

  4. The reader acquires. 读者获得了。

Notice how these 4 operations will necessarily have to happen in this order. 请注意这4个操作必须按此顺序进行。 Writing to mItem is guaranteed to be between 2 and 3 and reading would have to happen after 4 . 写入mItem保证在23之间,读取必须在4之后进行。 Combined with tiling these two threads still preserves this property implies the program is fine. 结合平铺这两个线程仍保留此属性意味着程序正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM