用info threads快速识别卡死线程:先执行info threads查看所有线程状态,重点关注处于Blocked或Waiting状态且栈顶为pthread_mutex_lock、std::mutex::lock或__lll_lock_wait的线程;若多个线程停在同一pthread_mutex_lock调用点且参数地址一致(如%rdi均为0x7fffe40012a0),说明争抢同一把锁;而停在read、nanosleep或poll但栈中无锁操作的线程大概率非死锁源头,可暂跳过。

怎么用 info threads 快速识别卡死线程
死锁时进程不崩溃也不退出,info threads 是你打开 GDB 后第一眼该看的命令。它列出所有线程 ID、状态和当前函数,重点盯三类线索:
- 状态为
Blocked或Waiting,且栈顶是pthread_mutex_lock、std::mutex::lock或__lll_lock_wait—— 这基本就是等锁线程 - 多个线程停在同一个
pthread_mutex_lock调用点,且参数地址一致(比如bt full看到%rdi都是0x7fffe40012a0)—— 说明争同一把锁 - 有线程停在
read、nanosleep或poll上,但调用栈里没锁操作——大概率不是死锁源头,先跳过
怎么用 thread 和 bt 定位具体锁争抢点
挑出一个疑似阻塞线程后,必须切换过去看完整路径,不能只信顶层函数名:
- 执行
thread 3(假设线程 ID 是 3),再执行bt查看全栈 - 顺着栈往回找:定位最靠近顶部的
pthread_mutex_lock或std::mutex::lock调用行(通常在倒数第 2–4 层) - 用
frame 5(数字按实际栈帧号)跳转到那层,再list看源码上下文,确认它试图加哪把锁(比如变量名是mtx_config还是mtx_cache) - 用
print &mtx_config或print *(pthread_mutex_t*)0x7fffe40012a0检查地址是否与其他线程一致
怎么交叉推断谁持有那把锁
Linux 的 pthread_mutex_t 默认不存持有者 ID,得靠行为反推:
- 如果线程 A 卡在
pthread_mutex_lock(&mtx_a),而线程 B 的栈顶是pthread_mutex_unlock(&mtx_a)或刚离开临界区(比如栈里有update_config→unlock→return),B 很可能刚释放mtx_a,但还没来得及拿其他锁 - 对
std::mutex,可尝试print ((std::mutex*)0x7fffe40012a0)->__lock(需调试符号支持):值为 0 表示未锁;非 0 值在 glibc 中常是持有者线程 ID(注意不是 GDB 线程号,是gettid()返回值) - 别依赖
info mutex—— 它在多数 glibc 版本中不生效或输出为空,纯属干扰项
怎么确认循环等待闭环
死锁本质是资源依赖图出现环,人工拼链路比靠工具更可靠:
- 线程 1:栈显示已执行
pthread_mutex_lock(&mtx_a),卡在pthread_mutex_lock(&mtx_b) - 线程 2:栈显示已执行
pthread_mutex_lock(&mtx_b),卡在pthread_mutex_lock(&mtx_a) - 此时闭环已成立。回到源码检查:是不是一个线程按
A→B顺序加锁,另一个按B→A?这种不一致就是根因 - 注意:若某线程栈里只有一次
lock调用且无对应unlock,可能是异常退出导致锁未释放——这也算一种“伪死锁”,但调用栈形态不同(通常卡在exit或abort附近)
bt 输出往往混着模板展开、内联函数和优化痕迹,别指望每层都干净。关键就两步:锁地址对得上 + 加锁顺序反着来。其他全是噪音。


















