GDB 调试多线程程序的总结

gdb 中step、next与finish的区别

step 就是单步执行,遇到子函数就进入并且继续单步执行;在其他调试其中相当于step-into命令,作用是移动到下一个可执行的代码行。如果当前行是一个函数调用,则调试器进入函数并停止在函数体的第一行。step可以帮助初步揭开代码位置的谜团,例如:函数调用和函数本身可能在不同的文件中。

next 是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。在其他调试器中相当于step-over,作用是在同一个调用栈层中移动到下一个可执行的代码行。调试器不会进入函数体。如果当前行是函数的最后一行,则,next将进入下一个栈层,并在调用函数的下一行停止。

finish 就是但单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数。在其他调试器中相当于step-out,作用是在栈中前进到到下一层,并在调用函数的下一行停止。

多线程的gdb调试

假设现在有一个主线程创建了一个子线程。

gdb调试时,设置断点,单步调试到pthread_create处的时候,这时候会创建子线程,会出现如下信息

[New Thread 0x7ffff6fd1700 (LWP 6376)]

默认情况下,gdb只跟踪主线程,新创建的线程都被阻塞在pthread_create函数处。

info threads 可以调试的所有线程,gdb会为每个线程分配一个ID,这个ID和线程ID不同,ID号一般从1开始。

如下,表示当前有两个线程1和2,*表示跟踪主线程1

(gdb) info threads
  Id   Target Id         Frame 
  2    Thread 0x7ffff6fd1700 (LWP 6376) "test" 0x00007ffff70d0851 in clone ()
   from /lib64/libc.so.6
* 1    Thread 0x7ffff7fee740 (LWP 6375) "test" main (argc=1, argv=0x7fffffffe2d8) at test.cpp:31

thread ID 切换当前调试的线程为指定ID号,ID是gdb分配的序号,不是线程TID。

set scheduler-locking off|on on锁定其他线程,只有当前选择调试的线程执行,off表示不锁定任何线程,当运行到断点处,将所有的线程都暂停下来,直到指定某个线程继续执行,如果在当前线程下使用continue的话会启动所有线程(GDB默认)。

多线程调试控制指令

thread apply ID1 ID2 ...IDn gdb_command 指定多个线程执行gdb中的command指令

thread apply all command 指定所有线程执行gdb中的command指令

non-stop模式

上面说过一个线程中断在一个断点上,其他所有的线程都会被freeze。新版本的GDB中,引入了non-stop模式,在这个模式下:

  1. 当某个或多个线程在一个断点上,其他线程仍会并行运行

  2. 你可以选择某个被中断的线程,只让他运行。

  3. non-stop模式表示不停止模式,除了断点有关的进程会被停下来,其他线程会继续执行。

设置non-stop模式,打开gdb后,在开始r之前,首先连续输入下面的指令

set target-async 1
set pagination off
set non-stop on

总结调试多线程的命令

info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程

thread ID(1,2,3…) 切换当前调试的线程为指定ID的线程

break thread_test.c:123 thread all(例:在相应函数的位置设置断点break pthread_run1) 在所有线程中相应的行上设置断点

thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command

thread apply all command 让所有被调试线程执行GDB命令command

set scheduler-locking 选项 command 设置线程是以什么方式来执行命令

set scheduler-locking off 不锁定任何线程,也就是所有线程都执行,这是默认值

set scheduler-locking on 只有当前被调试程序会执行

set scheduler-locking on step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行

线程池调试技巧

调试进程池和线程池中的程序一个不错的方法,是将池中的个数减少至1,观察是否正确,然后逐步增加线程数量,调试线程的同步是否正确

posted @ 2020-04-27 11:06  WindSun  阅读(1644)  评论(0编辑  收藏  举报
博客已停更,文章已转移,点击访问