简体   繁体   English

C ++内存排序

[英]C++ memory ordering

In some tutorial i saw such spin lock implementation 在一些教程中,我看到了这样的自旋锁实现

class spin_lock 
{
    atomic<unsigned int> m_spin ;

public:
    spin_lock(): m_spin(0) {}
    ~spin_lock() { assert( m_spin.load(memory_order_relaxed) == 0);}

    void lock()
    {
        unsigned int nCur;
        do { nCur = 0; }
        while ( !m_spin.compare_exchange_weak( nCur, 1, memory_order_acquire ));
    }
    void unlock()
    {
        m_spin.store( 0, memory_order_release );
    }
};

Do we really need memory_order_acquire / memory_order_release tags for compare_exchange_weak and store operations respectively? 我们是否真的需要memory_order_acquire / memory_order_release标签分别用于compare_exchange_weakstore操作? Or memory_order_relaxed is sufficient in this case as there is no Synchronizes-With relation? 或者memory_order_relaxed在这种情况下就足够了,因为没有Synchronizes-With关系?

Update: Thank you for the explanations! 更新:谢谢您的解释! I was considering spin_lock without context in which it is used. 我正在考虑spin_lock,没有使用它的上下文。

Yes memory_order_acquire / memory_order_release is needed. 是的memory_order_acquire / memory_order_release是必需的。

You use locks to protect shared data between multiple threads. 您使用锁来保护多个线程之间的共享数据。 if you don't use memory_order_release in unlock method, any write on shared data can be reordered after unlock method. 如果在unlock方法中不使用memory_order_release ,则可以在unlock方法后重新排序对共享数据的任何写入。 Also if you don't use memory_order_acquire in lock method any read on shared data can be reordered before lock method. 此外,如果您在lock方法中不使用memory_order_acquire ,则可以在lock方法之前重新排序对共享数据的任何读取。 so you need acquire/release to protect shared data between threads. 所以你需要acquire/release来保护线程之间的共享数据。

spinLock.lock() // use acquire here, so any read can't reordered before `lock`

// Writes to shared data

spinLock.unlock() // use release here, so any write can't reordered after `unlock`

with acquire/release all writes to shared data will be visible to threads that lock spinlock. 使用acquire/release对锁定自旋锁的线程可以看到对共享数据的所有写入。

With regard to memory_order_acquire / memory_order_release: consider the shared data (aka memory locations, or resource) that you are using the lock to protect. 关于memory_order_acquire / memory_order_release:考虑使用锁保护的共享数据(也称为内存位置或资源)。 I'll call that "the protected data". 我称之为“受保护的数据”。

The code needs to ensure that when lock() returns, any access to the protected data by the caller will read valid values (ie not stale values). 代码需要确保当lock()返回时,调用者对受保护数据的任何访问都将读取有效值(即不是过时值)。 memory_order_aquire ensures that the appropriate aquire memory barrier is inserted so that subsequent reads of the protected data (via the local CPU cache) will be valid. memory_order_aquire确保插入适当的aquire内存屏障,以便后续读取受保护数据(通过本地CPU缓存)将是有效的。 Similarly, when unlock() is called, memory_order_release is needed to ensure that the appropriate memory barrier is inserted so that other caches are correctly synchronised. 类似地,当调用unlock()时,需要memory_order_release以确保插入适当的内存屏障,以便正确同步其他缓存。

Some processors don't require aquire/release barriers and might, for a theoretical example, only require a full barrier in lock(). 某些处理器不需要获取/释放障碍,并且对于理论示例,可能仅需要lock()中的完整屏障。 But the C++ concurrency model needs to be flexible enough to support many different processor architectures. 但是C ++并发模型需要足够灵活以支持许多不同的处理器体系结构。

memory_order_relaxed is used in the destructor because this is just a sanity check to ensure that the lock isn't currently held. memory_order_relaxed在析构函数中使用,因为这只是一个完整性检查,以确保当前不保持锁。 Destructing the lock does not confer any synchronisation semantics to the caller. 破坏锁定不会给调用者带来任何同步语义。

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

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