std::atomic_flag 不提供加载或存储操作有什么缺点吗?(自旋锁示例)

j00*_*0hi 7 c++ atomic c++11 stdatomic

将 astd::atomic_flag与 an std::atomic_bool(又名std::atomic<bool>)进行比较,在我看来, astd::atomic_flag只是具有更简单的界面。它仅提供测试+设置和清除标志,同时std::atomic_bool还为多个运算符提供重载。

我的一个问题是关于术语的:“加载或存储操作”是什么意思?这是否意味着不能任意读取和修改 astd::atomic_flag的值?

此外,我想知道,将 astd::atomic_bool用于自旋锁时会更快吗?在我看来,std::atomic_flag在自旋锁期间总是必须读取和写入:

while (my_atomic_flag.test_and_set()); // spin-lock
Run Code Online (Sandbox Code Playgroud)

而 anstd::atomic_bool只需执行读取操作(假设原子 bool 是无锁实现的):

while (my_atomic_bool); // spin-lock
Run Code Online (Sandbox Code Playgroud)

严格来说,a 是否std::atomic_flag比 a 更有效率std::atomic_bool,或者反过来也可能吗?自旋锁应该使用什么?

LWi*_*sey 4

“加载或存储操作”是什么意思?这是否意味着无法任意读取和修改 std::atomic_flag 的值?

. 不支持正常的存储/加载操作std::atomic_flag
它是只修改类型;IE。std::atomic_flag如果不执行修改操作,则无法读取访问对象。
一般来说,std::atomic_flag它是作为其他操作的构建块。它的界面故意简单;它是唯一保证原子无锁操作的原子类型。它支持的操作有:

std::atomic_flag::clear()
std::atomic_flag::test_and_set()
Run Code Online (Sandbox Code Playgroud)

这样,您就可以轻松构建自己的自旋锁(尽管通常不推荐):

class my_spinlock {
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:

    void lock()
    {
        while(flag.test_and_set());
    }

    void unlock()
    {
        flag.clear();
    }
};
Run Code Online (Sandbox Code Playgroud)

此外,我想知道,将 std::atomic_bool 用于自旋锁时是否会更快?在我看来, std::atomic_flag 始终必须在自旋锁期间读取和写入

事实是,自旋锁在获取锁时总是必须修改其状态。你根本无法在不告诉别人的情况下获取锁。基于 a
的实现看起来非常相似:lock()std::atomic<bool>

while (flag.exchange(true)); 
Run Code Online (Sandbox Code Playgroud)

基于的自旋锁是否std::atomic_flag更快?
在我的平台上,编译器为两种类型发出相同的程序集,因此我会感到非常惊讶。

  • @ixSci:我的理解是,您通常希望以只读方式旋转,直到看到可用的锁,然后尝试获取它。然后,高速缓存行可以在所有等待线程中处于“共享”状态,而不是让它们全部用无效请求淹没总线以获取其独占所有权并将其反弹。这个答案最后一部分的问题是“atomic&lt;bool&gt;::exchange”不是一个好的实现,但是你不能用“atomic_flag”写出更好的东西。请参阅[通过内联汇编锁定内存操作](/sf/answers/26071/​​46263) (2认同)