应在线程函数入口设断点而非pthread_create,因后者是glibc内部实现,与业务逻辑无关;需先run再b worker,且set scheduler-locking off确保新线程可执行。

直接在 pthread_create 函数名上设断点,GDB 会停在它的第一行汇编指令处——但这通常不是你真正想要的。你真正关心的是「主线程调用 pthread_create 的那一行」,或者「新线程刚进入 start_routine 时的第一条语句」。这两者完全不同,设错位置会导致调试完全脱节。
为什么不能只用 b pthread_create
因为 pthread_create 是 libc 实现的函数,内部包含线程栈分配、TLS 初始化、系统调用(clone)等复杂逻辑。你在它入口打断点,看到的是 glibc 源码或汇编,和你的业务线程函数毫无关系;而且一旦 GDB 停在这里,你很难准确判断是第几个线程、参数是否已就绪。
- 你看到的堆栈里没有你的
thread_func,只有__pthread_create_2_1或类似符号 - 此时
arg参数可能还没被复制进新线程栈,print *(int*)$rdi类操作容易读到垃圾值 - 多个线程连续创建时,这个断点会被反复触发,干扰主线程流程
正确做法:在你的线程函数入口设断点
这才是最稳定、最贴近调试意图的方式。假设你的线程启动函数叫 worker:
- 编译时确保带
-g:gcc -g -o app app.c -lpthread - 启动 GDB 后,先
run让程序跑起来(否则worker符号可能未加载) - 等看到第一个线程创建后,再执行
b worker—— 此时 GDB 能解析出符号并绑定到实际代码段 - 如果想让所有线程都在入口停下,可加
catch syscall clone配合stepi,但太重,不推荐日常使用
想精确控制某次 pthread_create 调用?用条件断点
如果你的主线程里有多处 pthread_create 调用,且只想在第 N 次触发时中断,可以结合行号 + 条件:
- 先用
list找到调用pthread_create的源码行,比如main.c:42 - 设条件断点:
b main.c:42 if thread_id == 3(前提是thread_id是当前作用域可见变量) - 或者用计数器:
b main.c:42,然后ignore 1 2忽略前两次命中 - 注意:条件中不能访问刚传给线程的
arg内容,因为此时它可能还没被写入新线程上下文
多线程下避免误停:关掉 scheduler-locking
默认 GDB 只让当前线程运行,其他线程挂起。这会导致 pthread_create 后新线程根本无法真正启动,你的 worker 断点永远不会被 hit。
- 务必在
run前执行:set scheduler-locking off - 否则你会卡在
pthread_create返回前,看不到任何子线程活动 - 配合
info threads和thread apply all bt观察各线程状态
最容易被忽略的一点:GDB 加载符号有延迟。不要在 gdb ./app 后立刻 b worker,而要先 run 至少一次(哪怕立刻 ctrl+c),让动态链接器把 libpthread 符号加载进来,否则断点会变成 pending,后续无法触发。


















