info threads 的 id 是 gdb 分配的会话内序号(从1开始),仅用于 thread 命令切换;target id 中的 lwp 数字才是系统级线程 id,对应 /proc/pid/task/lwp 目录,不可混用。

info threads 命令显示的 Id 和 Target Id 分别是什么
info threads 输出里第一列叫 Id,是 GDB 自己分配的调试编号(从 1 开始递增),只在当前 GDB 会话中有效;第二列 Target Id 才是系统级线程标识,Linux 下通常形如 Thread 0x7ffff6e2b700 (LWP 31773) ——其中 LWP 31773 就是内核调度用的轻量级进程 ID(即系统线程 ID),和 ps -aL 或 /proc/PID/status 里看到的 Tgid/Pid 字段对应。
为什么不能直接用 info threads 的 Id 当作系统线程 ID
因为 Id 是 GDB 动态维护的序号,重启 GDB、detach 后 re-attach、甚至线程退出再新建,都可能导致编号重排。而真实调试时经常要交叉比对:ps -aLf | grep PID 看到的 LWP 列、pstack PID 输出里的线程地址、或者 /proc/PID/task/ 目录下的子目录名,这些全依赖系统 ID。
- 错误做法:记下
info threads里Id 2,然后去/proc/PID/task/2查状态 —— 这个路径根本不存在 - 正确做法:从
Target Id提取括号内的数字,比如(LWP 31773)→ 对应/proc/PID/task/31773/ - 注意 Solaris 等平台
Target Id格式不同,可能只写Thread 3 (LWP 3),此时 LWP 数字仍可直接用
快速提取系统线程 ID 的实操技巧
手动看 info threads 太慢,尤其线程多时。可以用 GDB 内置命令批量导出:
- 用
threadapply all p $_thread打印每个线程的 GDB 内部线程句柄(非系统 ID) - 更实用的是结合 shell:在 GDB 外执行
ps -aLo pid,lwp,comm -p PID | grep -v LWP,直接列出所有 LWP - 如果已进 GDB,用
shell ps -aLo lwp,pid,comm -p `pidof your_program` | grep -v LWP也能拿到实时映射 - 调试中想确认某线程是否卡在 syscall,可切过去后执行
info registers,看rip是否停在clone、nanosleep等内核入口点附近
切换线程时 thread 命令认的是哪个 ID
thread 命令后面跟的必须是 info threads 第一列的 Id,不是 LWP。例如输出里有 * 1 Thread 0x... (LWP 1234),你想切过去就得输 thread 1,输 thread 1234 会报错 Thread ID not known。
容易被忽略的一点:GDB 默认只让当前线程单步或继续,其他线程挂起。如果要观察多线程并发行为,得先执行 set scheduler-locking off,否则 continue 后只有当前线程跑,其余静止——这会让竞态问题根本复现不出来。











