可行,关键在于识别pstack输出中多个线程是否均卡在pthread_mutex_lock等锁函数且调用栈不变,结合多次采样比对与状态验证来确认环形等待僵持。

直接用 pstack 打印多线程程序死锁时的调用栈是可行的,但关键不在“怎么打”,而在“怎么看出来是不是死锁”——pstack 本身不判断死锁,它只如实呈现每个线程卡在哪一行、哪个函数、是否在等锁。
确认进程状态和权限前提
死锁进程通常仍在运行(R 或 S 状态),不是 D 状态;若看到 ps -o pid,comm,state -p $PID 显示 D,pstack 会失败,需换 gdb 方式。你还得满足:
- 目标进程由你启动,或你有 sudo 权限(否则 Permission denied)
- 系统已安装 gdb(pstack 是 gdb 封装,缺 gdb 会报 command not found)
- Ubuntu/Debian 等发行版若启用了
ptrace_scope=1,普通用户无法 attach 进程,需临时设为 0:echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
执行 pstack 并识别死锁线索
运行:pstack $PID
输出中每组以 Thread N (LWP XXXX): 开头,重点看以下几类调用帧:
- 反复出现在 __lll_lock_wait、pthread_mutex_lock、sem_wait 的线程——大概率在争同一把锁
- 多个线程堆栈都停在同一个锁操作(比如都卡在
libpthread.so.0的__lll_lock_wait),且各自持有别的锁 → 典型环形等待 - 对比多次采样(间隔 2–3 秒再跑一遍 pstack):如果所有线程的栈顶地址和函数名完全不变,基本可判定僵持
结合符号信息提升定位精度
若程序编译时加了 -g 或系统装了 debuginfo 包(如 glibc-debuginfo),pstack 输出会带源码行号,例如:
这时就能快速跳到 lock.c 第 47 行查锁顺序。没有符号时大量显示 ??() 或只有地址,只能靠函数名+so 名称推测(如 libstdc++.so.6 中的 __gthread_mutex_lock)。
辅助验证:用 ps + lsof 缩小范围
单靠 pstack 不足以 100% 确认死锁,建议搭配:
-
ps -T -p $PID查看线程数和状态(RUNNING/SLEEPING) -
lsof -p $PID | grep lock看是否打开了特殊锁文件(如 flock 场景) - 对疑似线程 LWP 号,查
/proc/$PID/task/$LWPID/status | grep State,确认是否真处于不可中断等待











