GDB是*nix下常用的调试工具,可以提供及其复杂的调试功能,功能十分强大。这里展示一下GDB调试多线程的常规方法。
常用命令:
info threads :显示当前可以调试的所有线程。
thread IDx : IDx请用上述命令中的线程ID替换,该命令用于切换被调试的线程,请注意GDB只能调试一个执行序列,也就一个传统意义上的进程
break file.c:20 thread all:在file.c中的第20行,为所有经过这里的线程设置断点
set scheduler-locking off|on|step:线程之间是并行执行的,step之类的命令会对所有线程生效。该命令就是提供了一种只对单一线程生效的解决方式。选项off表示不锁定任何进程,也就是默认情况。on表示命令只对当前线程生效。step表示在单步的时候,除了next过一个函数的情况以外,只对当前线程执行。
使用举例:
执行会提示segment错误,并提示产生coredump。但是却没有产生。需要执行ulimit -c unlimited。再执行一次,才真正的产生了coredump文件。
执行gdb a.out corefile 并执行bt查看执行backtrace,显示第49行执行错误。也就是初步怀疑线程1运行有问题。
执行
gdb a.out
(gdb) b 49
(gdb) thread 2 //主线程是1
(gdb) c
之后发现线程2工作正常,同理对线程2,也正常。按理pthread_join()是库函数不应该有问题,仔细检查发现,XX的笔误。这里提供了单独调试线程的方法,各位可以一试。
应用2,代码是修正笔误的上述代码,这里假设上述代码已经处于运行状态,但是跑飞了,需要确定各线程执行位置。
常用命令:
info threads :显示当前可以调试的所有线程。
thread IDx : IDx请用上述命令中的线程ID替换,该命令用于切换被调试的线程,请注意GDB只能调试一个执行序列,也就一个传统意义上的进程
break file.c:20 thread all:在file.c中的第20行,为所有经过这里的线程设置断点
set scheduler-locking off|on|step:线程之间是并行执行的,step之类的命令会对所有线程生效。该命令就是提供了一种只对单一线程生效的解决方式。选项off表示不锁定任何进程,也就是默认情况。on表示命令只对当前线程生效。step表示在单步的时候,除了next过一个函数的情况以外,只对当前线程执行。
使用举例:
应用1,下面代码会产生coredump,我们调试之。
#include <stdio.h>
#include <pthread.h>
int a(void){
sleep(2);
return 0;
}
int b(){
a();
return 0;
}
int c(){
b();
return 0;
}
void *myThread1(void)
{
int i=9;
while(i>0)
{
printf("Our 1st pthread,created by chn89.\n");
sleep(2);
i--;
c();
}
pthread_exit(0);
}
void *myThread2(void)
{
int i=5;
while(i>0)
{
printf("Our 2st pthread,created by chn89.\n");
sleep(2);
i--;
}
pthread_exit(0);
}
int main()
{
int ret=0;
pthread_t thread_id1,thread_id2;
ret = pthread_create(&thread_id1, NULL, (void*)myThread1, NULL); //这里笔误,应为thread_id1 就是调试这里的错误
if (ret)
{
printf("Create pthread error!\n");
return 1;
}
ret = pthread_create(&thread_id2, NULL, (void*)myThread2, NULL);
if (ret)
{
printf("Create pthread error!\n");
return 1;
}
pthread_join(thread_id1, NULL);
pthread_join(thread_id2, NULL);
return 0;
}
编译之 gcc pthread_gdb.c -g -lpthread
执行会提示segment错误,并提示产生coredump。但是却没有产生。需要执行ulimit -c unlimited。再执行一次,才真正的产生了coredump文件。
执行gdb a.out corefile 并执行bt查看执行backtrace,显示第49行执行错误。也就是初步怀疑线程1运行有问题。
执行
gdb a.out
(gdb) b 49
(gdb) thread 2 //主线程是1
(gdb) c
之后发现线程2工作正常,同理对线程2,也正常。按理pthread_join()是库函数不应该有问题,仔细检查发现,XX的笔误。这里提供了单独调试线程的方法,各位可以一试。
应用2,代码是修正笔误的上述代码,这里假设上述代码已经处于运行状态,但是跑飞了,需要确定各线程执行位置。
gdb a.out pid -- pid是运行的进程号
(gdb) thread 2
(gdb) bt
#0 0x00855416 in __kernel_vsyscall ()
#1 0x00bf1086 in nanosleep () from /lib/libc.so.6
#2 0x00bf0ea4 in sleep () from /lib/libc.so.6
#3 0x08048516 in a () at pthread_gdb.c:5
#4 0x08048528 in b () at pthread_gdb.c:10
#5 0x0804853a in c () at pthread_gdb.c:15
#6 0x08048571 in myThread1 () at pthread_gdb.c:26
#7 0x00cede99 in start_thread () from /lib/libpthread.so.0
#8 0x00c2cd2e in clone () from /lib/libc.so.6
可以看出线程1的backtrace,正在执行函数a中的sleep呢。