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

同一线程中shared_lock与unique_lock共享std::shared_mutex是否合法及死锁原因

同一线程中std::shared_lock与std::unique_lock能否共享std::shared_mutex?

这种做法不符合C++标准定义,必然会引发死锁,具体原因和正确处理方式如下:

1. 标准对shared_mutex锁转换的明确限制

C++标准规定,std::shared_mutex不支持同一线程从共享锁(shared_lock)直接升级为独占锁(unique_lock)。当线程持有共享锁时,尝试获取独占锁的操作会无限阻塞——因为独占锁要求所有共享锁(包括当前线程持有的)全部释放,而当前线程正拿着共享锁等待独占锁,形成了自循环的阻塞逻辑。

你代码里用std::adopt_lock属于完全误用:这个参数的含义是「当前线程已经持有该互斥量的独占锁」,但此时你持有的是共享锁,不仅不符合参数要求,还会触发未定义行为,本质上还是没释放共享锁就去抢独占锁,死锁是必然结果。

2. 死锁的具体触发逻辑

你的代码执行流程中:

  • 线程先获取shared_lock,此时mutex处于共享锁定状态,允许其他线程也获取共享锁。
  • 接着尝试用unique_lock获取独占锁,而独占锁的获取条件是「无任何线程持有共享锁或独占锁」。但当前线程自己还握着一个共享锁,这个获取操作会一直阻塞,直到自己释放共享锁——但它又在等独占锁获取成功,直接形成自死锁。

如果此时还有其他线程持有共享锁,情况会更复杂:当前线程等其他线程释放共享锁,其他线程可能也在等待独占锁,最终形成多线程交叉死锁。

3. 正确的处理方式

方式一:先释放共享锁,再获取独占锁

如果不需要原子性的锁升级,可以先完全释放共享锁,再获取独占锁:

std::shared_mutex mutex;
 
void foo() {
    {
        std::shared_lock readLock{ mutex };
        // ... 只读操作逻辑 ...
    } // 共享锁在此处释放
    {
        std::unique_lock lock{ mutex };
        // ... 读写操作逻辑 ...
    }
    {
        std::shared_lock readLock{ mutex };
        // ... 后续只读操作逻辑 ...
    }
}

注意:这种方式会失去共享锁到独占锁之间的原子性——释放共享锁和获取独占锁的间隙,其他线程可能修改数据。

方式二:用原子升级锁(C++17及以上)

如果需要原子性的锁升级,可以使用std::upgrade_lock配合std::shared_mutex的升级接口:

std::shared_mutex mutex;
 
void foo() {
    std::upgrade_lock upgradeLock{ mutex }; // 先获取可升级的共享锁
    // ... 只读操作逻辑 ...
    {
        std::unique_lock lock{ std::move(upgradeLock) }; // 原子性升级为独占锁
        // ... 读写操作逻辑 ...
    } // 独占锁释放,回到可升级共享锁状态
    // ... 后续只读操作逻辑 ...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:22:12