GDB调试多进程与多线程
Linux下工作,使用VIM编辑器,调试使用GDB。如同金科玉律一般,但熟练使用得费些力气才行。
VIM编辑器,要熟练各种快捷键,否则,对于新手,简直就是噩梦!
GDB调试器,相比GUI界面,使用起来不那么直观,但功能很强大!
本文以nghttp2的多进程/线程调试为例。
入正题!
1 多进程[process]与多线程[thread]
我们写的比较多的是多线程程序,一个进程下开启了多个线程。而多进程的程序很少涉及到。(线程与进程的区别不赘述!)。多进程的程序一般是服务器程序,比如 nginx , nghttp2 等,在启动的时候,会有一个master进程与一个或者多个worker进程被创建,master进程的任务就是对worker进程进行管理,worker进程主要处理业务。而每个worker进程下可能又会有一个或者多个线程在运行。
2 进程号PID
启动一个程序的时候,一般会有对应的进程号 PID,服务器程序会有master进程与worker进程,因为是worker进程在处理业务,所以,我们需要worker进程的 PID
一般master进程在上,worker进程在下,worker进程号也一般大于master进程号,这与创建顺序有关。
得到进程号,然后就可以启动GDB进行调试了。
3 多进程调试方法
3.1 attach PID
attach是调试进程的最常用办法,只要有可执行程序以及相应PID即可。如果程序运行太快,来不及attach 怎么办?
可以采用延时进入主程序的方法,比如在进程启动后,设定sleep一段时间,如10s的时间来attach。方法1需要sleep,方法2不需要,可以直接在gdb中控制程序运行,直接调试。
3.2 set follow-fork-mode child
设置GDB
set follow-fork-mode child
gdb将在fork之后直接执行子进程,直到断点处停止。
以nghttpx实例
提供两种方式,一种是先运行多进程程序,一种是使用gdb来带参数运行。
方法1:
- 启动,多进程程序。 nghttpx –conf=conf/nghttpx.conf
- 查看worker进程PID, ps -ef | grep nghttpx
- 启动gdb
- attach PID (worker进程)
- 设置断点,等等,
- 发送请求,开始调试
方法2 :
- gdb bin/nghttpx
- 设置参数 set args –conf=conf/nghttpx.conf
- 设置 set follow-fork-mode child,gdb将在fork之后直接执行子进程 // 不设置,不能调试
- 设置断点 ,等等
- run
- 发送请求,开始调试
4 多线程调试
4.1 GDB多线程调试的基本命令
info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程。
thread ID 切换当前调试的线程为指定ID的线程。break thread_test.c:123 thread all 在所有线程中相应的行上设置断点
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过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。
4.2 实例
用 thread THREADNUMBER 进行切换,THREADNUMBER 为上文提到的线程号1,2,3,4。下例显示将活动线程从 1 切换至 4。
后面就是直接在你的线程函数里面设置断点,然后continue到那个断点,一般情况下多线程的时候,由于是同时运行的,最好设置 set scheduler-locking on
这样的话,只调试当前线程