繁体   English   中英

C ++ 11使用<atomic>实现Spinlock

[英]C++11 Implementation of Spinlock using <atomic>

我实现了SpinLock类,如下所示

struct Node {
    int number;
    std::atomic_bool latch;

    void add() {
        lock();
        number++;
        unlock();
    }
    void lock() {
        bool unlatched = false;
        while(!latch.compare_exchange_weak(unlatched, true, std::memory_order_acquire));
    }
    void unlock() {
        latch.store(false , std::memory_order_release);
    }
};

我实现了上面的类,并创建了两个线程,每个线程调用一个相同的Node类实例的add()方法1000万次。

不幸的是,结果不是2000万。 我在这里错过了什么?

问题是compare_exchange_weak一旦失败就会更新unlatched变量。 compare_exchange_weak的文档:

将原子对象包含的值的内容与预期值进行比较: - 如果为true,则用val替换包含的值(如store)。 - 如果为false,则将其替换为包含的值。

即第一失败后compare_exchange_weakunlatched将更新为true ,那么下一个循环周期将尝试compare_exchange_weak truetrue 这成功了,你只是拿了一个由另一个线程持有的锁。

解决方案:确保设置unlatchedfalse每个前compare_exchange_weak ,如:

while(!latch.compare_exchange_weak(unlatched, true, std::memory_order_acquire)) {
    unlatched = false;
}

正如@gexicide所提到的,问题是compare_exchange函数使用原子变量的当前值更新expected变量。 这也是为什么你必须首先使用未unlatched的局部变量的原因。 要解决此问题,您可以在每次循环迭代中将unlatched设置为false。

但是,使用std::atomic_flag来代替使用compare_exchange ,而不是使用compare_exchange ,它更适合使用std::atomic_flag

class SpinLock {
    std::atomic_flag locked = ATOMIC_FLAG_INIT ;
public:
    void lock() {
        while (locked.test_and_set(std::memory_order_acquire)) { ; }
    }
    void unlock() {
        locked.clear(std::memory_order_release);
    }
};

资料来源: cppreference

手动指定内存顺序只是一个次要的潜在性能调整,我从源代码复制。 如果简单性比最后一点性能更重要,您可以坚持使用默认值并只调用locked.test_and_set() / locked.clear()

顺便说一句: std::atomic_flag是唯一保证无锁的类型,虽然我不知道任何平台, std::atomic_bool上的std::atomic_bool不是免费的。

更新:正如@David Schwartz,@ Anton和@Technik Empire的评论中所解释的那样,空循环有一些不良影响,如分支未预测,HT处理器上的线程饥饿和过高的功耗 - 所以简而言之,这是一个非常低效的等待的方式。 影响和解决方案是架构,平台和应用程序特定的。 我不是专家,但通常的解决方案似乎是在linux上添加cpu_relax()或在循环体上添加窗口上的YieldProcessor()

EDIT2:为了清楚起见:这里提供的便携版本(没有特殊的cpu_relax等指令)应该足以满足许多应用程序的要求。 如果你的SpinLock旋转很多,因为其他人持有锁很长时间(这可能已经表明一般的设计问题),最好还是使用普通的互斥锁。

暂无
暂无

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

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