You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于std::atomic<bool>的简易线程锁存在何种线程安全隐患?

自旋锁实现的线程安全问题

问题代码

struct MySimpleThreadLock
{
    constexpr MySimpleThreadLock() : bIsLocked(false) {}
    std::atomic<bool> bIsLocked;

    void lock()
    {
        while (bIsLocked);
        bIsLocked.store(true);
    }
    void unlock()
    {
        bIsLocked.store(false);
    }
};

void func()
{
    static MySimpleThreadLock my_lock;

    my_lock.lock();

    // DO SOMETHING 

    my_lock.unlock();
}

问题分析

完全有可能出现你描述的情况。

当前的lock()方法存在致命的线程安全漏洞:自旋等待while (bIsLocked);与后续的bIsLocked.store(true)是两个独立的操作,没有原子性保障。

具体场景:

  • 线程1持有锁时,bIsLocked为true,线程2、3进入自旋循环等待。
  • 线程1执行unlock()将bIsLocked设为false后,线程2和线程3的自旋循环会同时检测到bIsLocked为false,于是都退出循环。
  • 紧接着两个线程会先后(甚至在多核CPU下几乎同时)执行bIsLocked.store(true),最终两个线程都认为自己成功获取了锁,同时进入临界区,导致数据竞争或其他线程安全问题。

修复方案

要解决这个问题,必须把“检查锁状态”和“设置锁为锁定状态”合并为一个原子操作,标准做法是使用std::atomic的compare_exchange_weak或compare_exchange_strong方法:

void lock()
{
    bool expected = false;
    // 循环尝试原子交换:如果当前锁是未锁定状态(false),则将其设为锁定状态(true)
    while (!bIsLocked.compare_exchange_weak(expected, true))
    {
        expected = false; // 每次失败后重置expected,因为compare_exchange_weak会更新expected为当前值
    }
}

compare_exchange_weak是原子操作,它会原子性地完成以下逻辑:

  1. 比较bIsLocked的当前值与expected的值。
  2. 如果相等,将bIsLocked的值设为true,返回true,表示成功获取锁。
  3. 如果不等,将expected更新为bIsLocked的当前值,返回false,继续循环等待。

这样就能确保同一时刻只有一个线程能成功获取锁,避免多线程同时进入临界区的问题。


内容的提问来源于stack exchange,提问作者Zebrafish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:52:51