C ++内存排序

时间:2013-12-24 06:33:19

标签: c++ c++11 memory-model

在一些教程中,我看到了这样的自旋锁实现

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 );
    }
};

对于memory_order_acquirememory_order_release操作,我们是否真的需要compare_exchange_weak / store个标记?或者memory_order_relaxed在这种情况下就足够了,因为没有Synchronizes-With关系?

更新:谢谢您的解释!我正在考虑没有使用它的上下文的spin_lock。

2 个答案:

答案 0 :(得分:10)

需要memory_order_acquire / memory_order_release

您使用锁来保护多个线程之间的共享数据。如果您不在memory_order_release方法中使用unlock,则可以在unlock方法之后重新排序对共享数据的任何写入。此外,如果您不在memory_order_acquire方法中使用lock,则可以在lock方法之前重新排序对共享数据的任何读取。所以你需要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`
带有acquire/release

对锁定自旋锁的线程可以看到对共享数据的所有写入。

答案 1 :(得分:3)

关于memory_order_acquire / memory_order_release:考虑使用锁保护的共享数据(a.k.a.内存位置或资源)。我称之为“受保护的数据”。

代码需要确保当lock()返回时,调用者对受保护数据的任何访问都将读取有效值(即不是过时值)。 memory_order_aquire确保插入适当的aquire内存屏障,以便后续读取受保护数据(通过本地CPU缓存)将是有效的。类似地,当调用unlock()时,需要memory_order_release以确保插入适当的内存屏障,以便正确同步其他缓存。

某些处理器不需要获取/释放障碍,并且理论上可能只需要lock()中的完整屏障。但是C ++并发模型需要足够灵活,以支持许多不同的处理器体系结构。

memory_order_relaxed在析构函数中使用,因为这只是一个完整性检查,以确保当前不保持锁定。破坏锁定不会给调用者带来任何同步语义。