卡死时应执行 thread apply all bt 查看所有线程调用栈,遇内核态等待可加 -q 跳过;配合 info threads 确认线程状态,用 thread apply all "bt full; info args; info locals" 获取完整上下文,避免仅依赖单一线程信息。

卡死时直接用 thread apply all bt
程序卡住不动,但没崩溃、没 core 文件,说明至少有一个线程在阻塞或死锁。这时不能只看当前线程的 bt,因为 GDB 默认停在你 attach 或中断时所在的线程,它可能只是个空闲线程。必须让所有线程“开口说话”:thread apply all bt 是最直接有效的命令——它会挨个切换到每个线程,执行一次 bt,输出全部调用栈。
thread apply all bt 的常见误操作和绕过方法
容易卡在以下几种情况:
- 某个线程正处在内核态不可中断等待(比如
__futex_abstimed_wait_common或epoll_wait),bt会卡住或超时;此时加-q(quiet)参数可跳过失败线程:thread apply all -q bt - 输出太长刷屏看不清,可在 GDB 启动前加
set pagination off,或运行中执行该命令 - 想快速定位“疑似卡死”的线程,先用
info threads看状态:S(sleeping)正常,R(running)可能真在忙,D(uninterruptible)大概率卡在系统调用里
需要更多信息?组合命令比单跑 bt 更有用
光看函数名不够,得知道它卡在哪一行、用了什么参数、局部变量值是多少。这时候别手敲多次命令,用双引号包起来一次性执行:
-
thread apply all "bt full; info args; info locals"—— 每个线程都输出完整堆栈 + 参数 + 局部变量 -
thread apply all "bt 5; info registers"—— 只看栈顶 5 层 + 寄存器,适合快速扫视上下文 - 注意:如果某线程已崩溃或栈损坏,
bt full可能报错或输出乱码,这时退回用bt即可
别忘了确认线程是否真的“活着”
有时候你以为卡死了,其实是线程已经退出、只剩主线程在等 join,或者被信号杀掉了但 GDB 还没刷新状态。务必先运行:
-
info threads—— 查看线程列表和状态(LWP ID、GDB 内部编号、状态字符) -
thread <n></n>(比如thread 2)—— 切换到具体线程再bt,验证它是否真有有效栈帧 - 若
info threads显示某线程状态为Z(zombie),说明它已终止,不用再查它的栈
真正卡死的问题,往往藏在看似“正常休眠”的线程里——比如一个线程停在 pthread_mutex_lock,另一个停在 pthread_cond_wait,而它们等的锁或条件变量没人释放/唤醒。这种细节,只有把所有线程的 bt 并排对照才能发现。











