其实,我们在VS编译器中用的调试工具是集成的软件,但是在Linux中有特定的工具GDB,其实这是一个很强的工具,我其实用的不是很6,其实这个真的强,希望大家和我一样努力的来学习使用GDB调试;在这先推荐一个大神陈皓,博客已经不更新了但是还是有很多内容比如GDB调试
其实在陈皓大神的这个系列中,我们可以get很多的技能;
GDB调试多进程
在GDB调试中,默认的调试是父进程,当我们在程序中fork出一个子进程后,就不能达到调试子进程的目的,因此,GDB中肯定就会设置调试子进程的
set follow-fork-mode child/parent
上述的命令就是在gdb中调试的时候可以选择gdb调试的是父进程还是子进程;
set follow-fork-mode child //GDB调试子进程
set follow-fork-mode parent //GDB调试父进程
我们先展示一下我们的测试代码:
//test.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id == 0)//child
{
int a = 0, i;
for(i = 0; i < 5; i++)
{
a += i;
}
}
else
{
int b = 1, j;
for(j = 1; j < 5; ++j)
{
b *= j;
}
}
return 0;
}
在GDB调试之前,我们队目标文件编译的时候必须在 编译后面加 -g才能正确的进入GDB的调试:
在上图中,我们可以看到我什么也没有添加的调试后,直接进入的父进程,跳过了子进程;所以:GDB默认调试的父进程;
结合上图,我们可以看到的是,在子程序调试完后,直接就到24行退出;
其实在我们这个GDB调试中,父进程也可以用 set follow-fork-mode parent,也可以直接调试,毕竟默认的也是调试父进程;
在GDB调试多进程中还有一个调试的命令: set detach-on-fork on/off;
两个命令的联系如下:
follow-fork-mode | detach-on-fork | 说明 |
---|---|---|
parent | on | GDB默认的调试方式;值调试主进程 |
child | on | 只调试子进程 |
parent | off | 同时调试两个进程,gdb跟主进程,子进程block在fork位置 |
child | off | 同时调试两个进程,gdb跟子进程,主进程block在fork位置 |
所以,我们可以用上述命令调试多进程的程序:
我们在看到所有运行的进程后,可以选择调试那个进程:
GDB调试多线程
//thread.c
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
void* thread1(void* arg)
{
while(1)
{
sleep(5);
printf("Hello\n");
}
}
void* thread2(void* arg)
{
while(1)
{
sleep(5);
printf("world\n");
}
}
int main()
{
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1, NULL, thread1, NULL);
pthread_create(&tid2, NULL, thread2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
线程创建提醒
在GNU/Linux上,如果gdb检测一个新的线程,会给出如下通知:
查询已经创建的线程
线程切换
thread threadno可以切换到指定的线程,threadno就是上面gdb分配的线程id号
锁定一个线程
默认情况下,gdb不锁定任何线程:在切换到线程2中后,打印的不只是线程2中的数据,也还有线程3中的内容:
可以使用set scheduler-locking on来锁定只有当前线程的操作:不会执行其他线程的结果
scheduler-locking | on | off | step |
---|---|---|---|
调试某个线程是其他线程是否执行 | 锁定其他线程,只有当前线程执行 | 不锁定任何线程,默认值 | 在单步时,只有被调试线程运行 |
线程调试的其他命令:
thread apply ID command:让ID线程执行命令command;
thread apply all command:让所有线程执行命令command;