这个锁的记忆障碍是否正确?

时间:2014-10-30 15:46:22

标签: c++ locking atomic spinlock

这是对的吗?我是否正确假设在std::atomic_flag上应用内存排序不为通用锁定提供同步?

#include <atomic>

class Spinlock
{
public:
    Spinlock(): f(ATOMIC_FLAG_INIT) {}

    void lock()
    {
        while(f.test_and_set(std::memory_order_relaxed));
        std::atomic_thread_fence(std::memory_order_acquire);
    }
    void unlock()
    {
        std::atomic_thread_fence(std::memory_order_release);
        f.clear(std::memory_order_relaxed);
    }

private:
    std::atomic_flag f;
};

我很抱歉,如果这是一个愚蠢的问题,但我觉得std::atmoic_thread_fence是一个通用锁定所必需的,并且memory_order_acquiretest_and_set { memory_order_release上的{1}}是不够的,但我也不确定。

2 个答案:

答案 0 :(得分:2)

总的来说,这是正确的。 由于您在test_and_set函数中使用了'std :: memory_order_relaxed',因此在没有'atomic_thread_fence'调用的情况下,没有任何东西会阻止在Mutex :: lock之前和之后完成的操作的重新排序。由于预期'Mutex :: lock'充当内存屏障,因此需要调用'atomic_thread_fence'。但我相信通过在'test_and_set函数'中使用'std :: memory_order_acquire'可以实现相同的效果。 看到这个: http://en.cppreference.com/w/cpp/atomic/atomic_flag

答案 1 :(得分:1)

通常的模式是使用test_and_set(memory_order_acquire)clear(memory_order_release)。但我怀疑你已经知道了。

根据标准第29.8节[atomic.fences](2):

  

释放栏A如果存在,则与获取栏B同步   原子操作X和Y,都在一些原子对象M上运行,   这样A在X之前被测序,X修改M,Y在之前被测序   B和Y读取由X写入的值或由任何一方写入的值   在假设的释放序列中,如果它是a,则X将会结束   释放操作。

在您的代码中,A是unlock()函数中的栅栏; X是clear(); Y是lock()函数中的栅栏;而B是test_and_set()。因此,您的代码符合标准此部分的要求,因此您的unlock()lock()函数已正确同步。