技术: 多线程调试问题

这里就单独拎出来总结一下 多线程, 多进程的调试问题.

调试多线程不一定用 gdb , 也可以用mdb(modular debugger)等其他工具(nptl trace tools 也是不错的工具) 当然我看到的高手调试, 不用工具, 直接加打印语句, 跑程序, 甚至面码. (不得不说, 高手其实是懒得学习使用别人的工具的…)

注: modula-3 supports user-space thread breakpoints.

引子

最常见的用GDB的方式, 莫过于:

  • All-Stop Mode: All threads stop when GDB takes control
  • Non-Stop Mode: Other threads continue to execute
  • Background Execution: Running your program asynchronously
  • Thread-Specific Breakpoints: Controlling breakpoints
  • Interrupted System Calls: GDB may interfere with system calls
  • Observer Mode: GDB does not alter program behavior

其他 gdb 的调试问题, 可以参考我的文章 linux下3大件儿

正文

调试多线程

如果你程序是多线程的话,你可以定义你的断点是否在所有的线程上,或是在某个特定的线程。
GDB很容易帮你完成这一工作:

1
2
break <linespec> thread <threadno>
break <linespec> thread <threadno> if

说明:

  • linespec指定了断点设置在的源程序的行号。
  • threadno指定了线程的ID,注意,这个ID是GDB分配的,你可以通过“info threads”命令来查看正在运行程序中的线程信息。如果你不指定thread 则表示你的断点设在所有线程上面。
  • if表示你还可以为某线程指定断点条件, 例如: (gdb) break frik.c:13 thread 28 if bartab > lim

当你的程序被GDB停住时,所有的运行线程都会被停住。这方便你你查看运行程序的总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行(哪怕主进程是被在单步调试)。

thread命令介绍:

  • info threads 显示当前可调试的所有线程,GDB为其分配的ID,后面操作线程的时候会用到这个ID (前面有*的是当前调试的线程)
  • thread ID 切换当前调试的线程为指定ID的线程
  • thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command
  • thread apply all command 让所有被调试线程执行GDB命令command
  • set scheduler-locking off|on|step 估计是实际使用过多线程调试的人都可以发现,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。
    • off 不锁定任何线程,也就是所有线程都执行,这是默认值
    • on 只有当前被调试程序会执行
    • step 在单步的时候,除了next过一个函数的情况以外,只有当前线程会执行

注意next其实也是借助break和continue实现的行为.

(GDB关于线程的实现思路要结合源码看, 需要一定技术水平, 我就不说了)

最后介绍一下我最近遇见的一个多线程调试和解决:

调试多线程程序不正常, info threads看不到多线程的信息. 用命令 maintenance print target-stack 看一下target的装载情况, 发现target “multi-thread”没有被装载, 用gdb对gdb程序调试发现在函数 check_for_thread_db 在调用 libthread_db中的函数 “td_ta_new” 的时候, 返回了TD_NOLIBTHREAD, 所以没有装载target “multi-thread”.
也就是说, libpthread可能有问题, 检查一下环境发现 libpthread是被strip过的(影响了td_ta_new函数对于libpthread符号信息的获取). 改换一个包含富含信息的(比如debug版本的)libpthread库到lib目录下, 问题解决了.

调试多进程

最先想到的就是 attach. attach: 用gdb调试一个正在运行中的进程 gdb <program> PID .

尾巴

文章目录
  1. 1. 引子
  2. 2. 正文
    1. 2.1. 调试多线程
    2. 2.2. 调试多进程
  3. 3. 尾巴
|