info threads显示的是GDB当前会话中已捕获且未退出的线程,即程序运行中被GDB通过线程事件(如clone完成)注册的活跃线程,不包括刚创建未调度或已退出未回收的线程;带*号的是当前调试焦点线程。

info threads 显示的是什么线程?
info threads 查到的不是操作系统级的所有线程,而是当前 GDB session 中“已知”的线程——通常是程序启动后被 GDB 捕获到的、且尚未退出的线程。它不显示刚创建还没被调度、或已退出但内核还没回收的线程。
常见误区是以为它等价于 ps -T -p <pid> 或 /proc/<pid>/task/ 列表,其实 GDB 只在收到线程事件(如 clone 系统调用完成)时才注册线程。如果线程创建后立刻退出,info threads 可能根本看不到它。
- 必须在程序运行中执行
info threads,停在断点或Ctrl+C中断后才有效;程序已退出时命令会报错No thread selected - 输出中带
*的是当前调试焦点线程(即你正在查看栈帧的那个),其他线程状态可能是running、sleeping或stopped(取决于是否被信号中断或主动等待) - 线程 ID 是 GDB 内部编号(如
Thread 2),不是 OS 的 TID(可通过thread apply all info registers或info thread单行查看其tid字段)
怎么切换到指定线程并查看它的调用栈?
不能直接用 OS 级 TID 切换,得用 info threads 输出左侧的 GDB 线程号(比如 2),再配合 thread <n> 命令。
例如:
立即学习“C++免费学习笔记(深入)”;
gdb-peda$ info threads Id Target Id Frame 1 Thread 0x7ffff7fca740 (LWP 12345) "a.out" 0x00007ffff7b8e6d0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84 * 2 Thread 0x7ffff77c9700 (LWP 12346) "a.out" 0x00007ffff7b8e6d0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84 3 Thread 0x7ffff6fc8700 (LWP 12347) "a.out" 0x00007ffff7b8e6d0 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84
想看线程 3 的栈,就输:thread 3,然后 bt。注意:切换后 print、step 等操作都作用于该线程,别误以为还在主线程上下文里。
- 切换线程不会自动刷新寄存器视图,需手动执行
info registers才能看到新线程的寄存器值 - 如果目标线程正处于系统调用阻塞中(如
read、pthread_cond_wait),bt可能只显示内核入口,此时可加bt full尝试展开用户态帧 - 对
std::thread创建的线程,GDB 通常能识别其函数名;但若用pthread_create传裸函数指针,栈顶可能只显示start_thread,需结合frame 1往上翻
为什么 info threads 有时只显示一个线程?
最常见原因是线程还没真正创建成功,或者 GDB 没启用线程事件捕获。C++11 std::thread 构造函数返回不等于线程已运行——它可能卡在 clone() 系统调用前,或刚进入但还没触发 GDB 的线程通知机制。
- 确认程序确实启动了多线程:在
std::thread构造后加一句std::this_thread::yield();,给调度器一点时间 - GDB 启动时加
-ex "set follow-fork-mode child"不管用——那是针对fork()的;多线程要用set follow-fork-mode parent(默认值)并确保没关线程跟踪:show schedule-multiple应为on - 某些发行版 GDB 编译时没开
--enable-libthread-db,会导致无法解析libpthread符号,从而漏掉线程;可用info sharedlibrary检查libthread_db.so.1是否已加载
info threads 和 thread apply all 的关键区别
info threads 是“查状态”,thread apply all <cmd> 是“批量执行”。后者会在每个线程上依次运行命令,但容易掩盖单个线程的异常行为。
比如 thread apply all bt 会打印所有线程栈,但如果某个线程正处在 signal handler 中,GDB 可能卡住或跳过它——而 info threads 能一眼看出哪个线程状态异常(比如显示 ??? 或 unknown)。
- 调试死锁时,优先用
info threads找出全部stopped线程,再逐个thread <n>+bt看它们卡在哪一行 -
thread apply all p $pc可快速定位所有线程当前指令地址,但要注意:不同线程的寄存器上下文独立,$pc值不能跨线程比较逻辑意义 - 避免无脑用
thread apply all step——这会让所有线程同时单步,极易破坏同步逻辑,几乎没实用价值
线程 ID 的歧义性最容易被忽略:GDB 线程号每次 run 会重排,OS TID 才是唯一标识。调试复杂场景时,建议先记下关键线程的 info thread 输出里的 tid,而不是依赖序号。


















