使用gdb来调试多线程、多进程
2017-06-16 19:23
141 查看
1、GDB基础调试命令介绍
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。gdb调试 使用的是 debug 版本的 ,所以 我们在生成可执行文件的时候 ,我们需要在命令尾部 加上 - g ,加上可以生成的是 debug版本下的可执行文件
gcc <filename> -g调试代码的基本命令:
2、使用GDB调试多线程运行
GDB默认是支持多线程调试的,但是要怎么来实现多线程的调试呢?gdb调试一般有两种模式:all-stop模式和no-stop模式(gdb7.0之前不支持no-stop模式)。
1.all-stop模式
在这种模式下,当你的程序在gdb由于任何原因而停止,所有的线程都会停止,而不仅仅是当前的线程。一般来说,gdb不能单步所有的线程。因为线程调度是gdb无法控制的。无论什么时候当gdb停止你的程序,它都会自动切换到触发断点的那个线程。
2.no-stop模式(网络编程常用)
顾名思义,启动不关模式。当程序在gdb中停止,只有当前的线程会被停止,而其他线程将会继续运行。这时候step,next这些命令就只对当前线程起作用。
如果需要打开no-stop模式,可以向~/.gdbinit添加配置文件:
#Enable the async interface
set target-async 1
#If using the CLI, pagination breaks non-stop
set pagination off
#Finall, turn it on
set non-stop on
gdb支持的命里有两种类型:前台的(同步的)和后台(异步 )的。区别很简单,同步的在输出提示符之前会等待程序report一些线程已经终止的信息,异步则是直接返回。所以我们需要set target-async 1。set pagination off不要出现 Type <return> to continue 的提示信息 。最后一步是打开。
下面是常用命令:
info threads 显示所有线程
thread id 切换到指定线程
break filename:linenum thread all 在所有线程相应行设置断点,注意如果主线程不会执行到该行,并且启动all-stop模式,主 线程执行n或s会切换过去
set scheduler-locking off\on\step 默认off,执行s或c其它线程也同步执行。
on,只有当前线程执行。 step,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后
continue的行为)以外,只有当前线程会执行
show scheduler-locking 显示当前模式
thread apply all command 每个线程执行同意命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。
主要是我们要用能用的上的,比如no-stop模式,一般多线程调试就很有用的。
下面使用代码来演示一下多线程的调试:
这是一份多线程的代码:
#include<stdio.h> #include<pthread.h> //实现线程的那部分代码 void * thread1(void * argc) { printf("pid : %d ,tid: %u\n",getpid(),pthread_self()); //在此处调用pthread_exit函数 pthread_exit(10); } void * thread2(void * argc) { printf("pid : %d ,tid: %u\n",getpid(),pthread_self()); return (void*)20; } int main() { pthread_t pthread1,pthread2; pthread_create(&pthread1,NULL,&thread1,NULL); pthread_create(&pthread2,NULL,&thread2,NULL); //调用线程取消函数 pthread_cancel(pthread2); //在此处调用线程等待函数 void * retval1= NULL; void * retval2= NULL; pthread_join(pthread1,&retval1); pthread_join(pthread2,&retval2); printf("thread1 ret is %d \n",retval1); printf("thread2 ret is %d \n",retval2); return 0; }开始调试:
单步运行:
切换线程2调试
切换到线程3调试
3、使用GDB实现多进程之间的调试
(1).单独调试子进程
我们可以先运行程序,然后再另一终端使用ps -ef | grep "main"(main此处是可执行文件名)搜索到子进程pid,然后启动gdb,在将其附加(attach)到gdb调试器上。attach child-pid 使用该命令后,直接run即可,和调试普通程序就没区别了
dettach 脱离进程
(2).使用调试器选项follow-fork-mode
我们知道如果不设置任何选项,gdb默认调试父进程。调试器选项用法如下:set follow-fork-mode mode 其中mode的可选值是parent和child,分别表示调试父进程和子进程。
info inferiors 查询正在调试的进程
inferior processnum 切换进程
默认设置下,在调试多进程程序时GDB只会调试主进程。但是GDB(>V7.0)支持多进程的分别以及同时调试,换句话说,GDB可以同时调试多个程序。只需要设置follow-fork-mode(默认值:parent)和detach-on-fork(默认值:on)即可。我们还可以使用catch fork指令,如果fork异常,会停止程序。
follow-fork-mode | detach-on-fork | 说明 |
parent | on | 只调试主进程(GDB默认) |
child | on | 只调试子进程 |
parent | off | 同时调试两个进程,gdb跟主进程,子进程block在fork位置 |
child | off | 同时调试两个进程,gdb跟子进程,主进程block在fork位置 |
下面是使用代码来实现多进程调试:
#include<stdio.h> #include<sys/types.h> #include<unistd.h> //这是一个多进程的代码 int main() { printf("start new process\n"); pid_t pid = fork();//使用fork函数生成子进程 if(pid == 0 ) { //子进程执行的代码 int count = 0; printf("child ! pid = %d,ppid = %d \n",getpid(),getppid()); sleep(1); } else { //父进程执行代码 printf("parent ! pid = %d,ppid = %d \n",getpid(),getppid()); sleep(1); } return 0 ; }
只调试父进程
只调试子进程(与上面的对比来看看)
同时调试两个进程(父进程调试 运行 ,子进程block(以阻塞方式等待))
同时调试两个进程(子进程调试 运行 ,父进程block(以阻塞方式等待))(对比上面的看)
相关文章推荐
- 多线程之问题的解决及使用GDB调试多线程多进程的手段(九)
- 使用GDB调试多进程/多线程程序
- 使用gdb调试多线程与多进程
- 使用gdb调试多进程及多线程程序
- 使用gdb调试多进程、多线程程序
- 使用gdb调试多进程和多线程程序
- Linux下使用gdb调试多进程与多线程程序
- 使用gdb调试多线程多进程程序
- 【Linux】使用gdb调试多进程&多线程
- 使用gdb调试多进程和多线程
- 使用gdb调试多进程与多线程程序
- GDB调试信号、多线程、多进程
- 使用 GDB 调试多进程程序
- gdb调试多进程与多线程
- 使用GDB调试多进程程序
- 使用GDB调试多进程程序
- [Flash/Flex] 使用gdb调试多线程FlasCC应用程序
- 使用 GDB 调试多进程程序
- 使用 GDB 调试多进程程序
- 用gdb调试多进程和多线程的服务器程序