这是对的吗?我是否正确假设在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_acquire
和test_and_set
{ memory_order_release
上的{1}}是不够的,但我也不确定。
答案 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()
函数已正确同步。