pstack不能直接标出“DEADLOCK”,但能通过多次输出比对发现线程长期卡在锁函数(如pthread_mutex_lock、__lll_lock_wait)且栈帧不变的死锁痕迹。

pstack 能直接看出死锁吗?
不能直接标出“DEADLOCK”字样,但能暴露死锁的典型痕迹:多个线程卡在同一个锁函数(比如 pthread_mutex_lock、__lll_lock_wait)且调用栈长期不变。关键不是看单次输出,而是比对多次 pstack <pid></pid> 的结果——如果某几个线程的栈帧完全一致、没有推进,且都停在锁等待位置,基本就是死锁了。
怎么看 pstack 输出里谁在等谁?
重点盯住每个线程的最顶层几行(#0、#1),尤其是系统调用和锁相关函数:
-
pthread_mutex_lock或__pthread_mutex_lock:说明线程正尝试加锁,但锁已被占用 -
__lll_lock_wait:glibc 内部实现的锁等待,常见于 pthread mutex 竞争 -
sem_wait、pthread_cond_wait:也可能涉及条件变量或信号量阻塞,需结合上下文判断是否构成循环等待 - 如果两个线程 A 和 B 的栈顶分别是
pthread_mutex_lock(&mutex_a)和pthread_mutex_lock(&mutex_b),而它们各自的下一层调用又分别试图获取对方持有的锁(比如 A 的 #2 是lock_b(),B 的 #2 是lock_a()),这就是典型的环路等待证据
执行 pstack 时容易忽略的细节
真实环境里,以下几点常导致误判或漏判:
- 进程必须有调试符号(编译时加
-g),否则栈里全是地址,看不出函数名;C++ 还得注意符号未被 strip,否则std::mutex::lock()可能显示为_ZNSt5mutex4lockEv - 不要只跑一次
pstack—— 死锁是状态,不是瞬间快照。建议间隔 2–3 秒连续执行 3 次:pstack <pid> > stack1.txt && sleep 2 && pstack <pid> > stack2.txt && sleep 2 && pstack <pid> > stack3.txt</pid></pid></pid> - 注意线程 ID(LWP)对应关系:
Thread 2 (Thread 0x7f8b3c000700 (LWP 12345))中的12345是内核线程号,可配合ps -T -p <pid></pid>验证是否真正在运行还是已僵死 - 如果看到大量线程卡在
nanosleep、poll或read,大概率不是死锁,而是 I/O 阻塞或业务逻辑休眠,别急着下结论
确认死锁后下一步怎么做?
光靠 pstack 定位到锁对象还不够,得知道是哪两个(或多个)锁在循环等待。这时需要:
立即学习“C++免费学习笔记(深入)”;
- 从栈里提取锁变量名或地址(比如
&g_mutex_a),再用gdb <pid></pid>附加后执行print *(pthread_mutex_t*)0x7f8b3c000ab0查看锁状态(是否 locked、owner tid) - 检查代码中所有涉及这些锁的加锁顺序,确认是否存在不一致(A 先 lock a 后 lock b,B 却先 lock b 后 lock a)
- 临时加日志:在每次
lock()前打印锁地址和当前线程 ID,比事后分析更可靠
真正难的不是发现死锁,而是还原出那几行交叉加锁的代码路径——pstack 提供的是现场快照,不是调用图谱。


















