前言
在多线程编程时,当我们需要调试时,有时需要控制某些线程停在断点,某些线程继续执行。有时需要控制线程的运行顺序。有时需要中断某个线程,切换到其他线程。这些都可以通过gdb实现。
下图为多线程与多进程调试的通用常用命令,应该熟练掌握下面几种命令的使用。
gdb调试多线程
多线程调试的主要任务是
准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结果就是维护一个叫thread list的链表。
下面我们以以下多线程的程序为例,在gdb模式下测试各种命令。
#include
#include
#include
int count = 0 ;
void * pthread_run ( void * arg)
{
int i = 0 ;
while ( i < 100 )
{
i++ ;
count + = i;
}
return NULL ;
}
int main ( )
{
pthread_t pth1;
pthread_t pth2;
pthread_create ( & pth1, NULL , & pthread_run, NULL ) ;
pthread_create ( & pth2, NULL , & pthread_run, NULL ) ;
pthread_join ( pth1, NULL ) ;
pthread_join ( pth2, NULL ) ;
printf ( "count: %d
" , count) ;
return 0 ;
}
① 在编译程序时加上-g。如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。使用gdb+可执行程序进入gdb调试模式。
② list [行号]:表示列出第几行附近的代码,默认显示10行,可以摁下l选项顺次列出(list可缩写为l)。
③ info break:查看断点信息。break [行号],表示在程序的第几行设置断点(break可简写为b)。
④ r:即run,表示运行程序。上面设置了断点,因此会在第一个断点处停住。
⑤ delete [断点号]:表示删除单个断点。delete 1-10:删除一个断点的集合,表示删除1到10所有的断点。
⑥ n:即next,单步调试模式,表示单条语句执行。
⑦ p [变量名]:打印变量的值,p为printf的缩写。
⑧ bt:查看函数的堆栈信息。
⑨ thread apply all bt:让所有线程都打印堆栈信息。thread apply ID command :让ID线程执行命令command。thread apply all command :让所有线程执行命令command。
⑩ info threads:显示当前可调试的所有线程,gdb为每一个线程分配一个ID号。*表示正在调试的线程。thread [线程ID]:切换到当前要调试的线程ID。
⑪ c:continue,与C/C++中的continue完全一致。
⑫ finish:退出当前函数(本例中为pthread_run)。
⑬ q:即quit,表示退出gdb模式。
gdb调试多进程
在Linux(CentOS6.5)默认设置下,调试多进程程序时gdb只会调试父进程,为了可以对父子进程都做到调试,我们需要做一些设置。
follow-fork-mode
detach-on-fork
具体说明
parent
on
只调试父进程
child
on
只调试子进程
parent
off
同时调试两个进程,gdb跟父进程,子进程block在fork位置
child
off
同时调试两个进程,gdb跟子进程,父进程block在fork位置
① show follow-fork-mode:查看当前调试的fork模式,如下图,默认为父进程,如果想设置为子进程,可以使用set follow-fork-mode child。
② show detach-on-fork:查看detach-on-fork的模式。设置为on表示只调试父子进程(与①的设置有关)中的一个,off表示父子进程都在gdb的控制之下,其中一个进程正常调试另一个进程会被设置为暂停状态。
③ info inferiors:显示gdb调试的所有进程。inferior [进程编号]:可以切换到特定的inferiors进行调试。其中*代表正在调试的进程。
④ maint info program-spaces:显示当前gdb一共管理了多少地址空间。
⑤ detach inferior [进程编号]:detach掉某一进程的编号,但是这个进程还存在,让它自由运行完,detach掉的进程会显示null。
⑥ kill inferior [进程编号]:kill掉某进程,但是此进程还存在,可再次使用run等命令执行它,被kill掉的进程会显示null。
⑦ remove-inferior [进程编号]:删除某一个inferior。如果该inferior正在运行,则不能删除,因此删除之前必须先kill或detach掉。
⑧ set schedule-multiple:设置为off表示只有当前的inferior会被执行,设置为on,表示所有执行状态的inferior都会被执行。
⑨ set print interior-events on/off:用来打开和关闭inferior状态的提示信息。
当然,gdb多线程的断点、单步调试、运行等命令同样适用于多进程的调试,这里也就不一一列举了。上述仅仅是一些常用命令的举例,想了解其他命令请自己动手尝试。