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

为何调用其他函数后lock_guard未析构?代码死锁问题咨询

为什么这段代码会引发死锁?

嘿,这个问题的核心原因其实是你用的默认std::mutex是非递归互斥锁,咱们来一步步捋清楚:

原代码的死锁逻辑

当你调用outside()时:

  • 第一行的lock_guard<mutex>会立即获取LOCK的所有权,此时当前线程持有这个锁。
  • 接着调用inside(),里面的lock_guard又尝试去锁同一个LOCK——但非递归互斥锁的规则是:同一个线程不能重复获取已经持有的锁。这时候线程会阻塞,等待LOCK被释放,但释放锁的动作只能由持有它的线程来做,而这个线程现在正卡在等待锁的状态,于是就形成了死锁。

至于你尝试用unique_lock结果一样,是因为unique_lock默认也是以非递归方式获取锁的,除非你搭配递归互斥锁使用,否则和lock_guard的行为没有本质区别。

手动解锁方法有效的原因

你修改后的outside()在调用inside()前手动解锁了LOCK,这时候inside()里的lock_guard可以正常获取到锁,不会触发阻塞,自然也就不会死锁。不过这种手动加解锁的方式容易出错(比如忘记解锁或者解锁时机不对),不是最优解。

更优雅的解决方案

这里有两种常用的解决思路:

1. 使用递归互斥锁std::recursive_mutex

递归互斥锁允许同一个线程多次获取锁,内部会维护一个计数:每次加锁计数+1,解锁计数-1,只有当计数归0时,锁才会真正被释放。把原来的std::mutex替换成std::recursive_mutex即可:

#include <mutex>
#include <iostream>

std::recursive_mutex LOCK;

void inside() { 
    std::lock_guard<std::recursive_mutex> lock(LOCK); 
    std::cout << "Finished inside" << std::endl; 
}

void outside() { 
    std::lock_guard<std::recursive_mutex> lock(LOCK); 
    inside(); 
    std::cout << "Finished outside" << std::endl; 
}

2. 重构代码,避免重复加锁

递归互斥锁会带来额外的性能开销,所以更推荐的方式是重构代码,把不需要锁的核心逻辑抽出来,让外层函数统一管理锁:

#include <mutex>
#include <iostream>

std::mutex LOCK;

// 抽取出无锁的核心逻辑
void inside_core() {
    std::cout << "Finished inside" << std::endl; 
}

void inside() { 
    std::lock_guard<std::mutex> lock(LOCK); 
    inside_core();
}

void outside() { 
    std::lock_guard<std::mutex> lock(LOCK); 
    inside_core(); // 直接调用无锁版本,避免重复加锁
    std::cout << "Finished outside" << std::endl; 
}

总结

死锁的本质是同一个线程尝试重复获取非递归互斥锁导致的自我阻塞。递归互斥锁可以直接解决问题,但重构代码减少不必要的锁嵌套通常是更高效、更安全的做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:14:50