多线程调试方法

来源:互联网 发布:最好的搏击软件 编辑:程序博客网 时间:2024/06/15 18:59


 

set target-async 1

set pagination off

set non-stop on

 

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

threadID 
切换当前调试的线程为指定ID的线程。 

breakthread_test.c:123 thread all
在所有线程中相应的行上设置断点

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


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

setscheduler-locking off|on|step 
估计是实际使用过多线程调试的人都可以发现,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。

 

 

 

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

on只有当前被调试程序会执行。 

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

 

 

作者:破砂锅

开源的GDB被广泛使用在LinuxOSXUnix和各种嵌入式系统(例如手机),这次它又带给我们一个惊喜。

多线程调试之痛

调试器(如VS2008和老版GDB)往往只支持all-stop模式,调试多线程程序时,如果某个线程断在一个断点上,你的调试器会让整个程序freeze,直到你continue这个线程,程序中的其他线程才会继续运行。这个限制使得被调试的程序不能够像真实环境中那样运行--当某个线程断在一个断点上,让其他线程并行运行。

GDBv7.0引入的non-stop模式使得这个问题迎刃而解。在这个模式下,

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

  • 你可以选择某个被断的线程,并让它继续运行

    让我们想象一下,有了这个功能后

  • 当其他线程断在断点上时,程序里的定时器线程可以正常的运行了,从而避免不必要得超时 

  • 当其他线程断在断点上时,程序里的watchdog线程可以正常的运行了,从而避免嵌入式硬件以为系统崩溃而重启

  • 可以控制多个线程运行的顺序,从而重现deadlock场景了。由于GDB可以用python脚本驱动调试,理论上可以对程序在不同的线程运行顺序下进行自动化测试。

    因此,non-stop模式理所当然成为多线程调试必杀技。这2009年下半年之后发布的Linux版本里都带有GDBv7.0之后的版本。很好奇,不知道VS2010里是不是也支持类似的调试模式了。

    演示GDBnon-stop模式

     

    让破砂锅用一个C++小程序在Ubuntu Linux09.10demo这个必杀技。虽然我的demo使用命令行版gdb,如果你喜欢图形化的调试器,Eclipse20095月之后的版本可以轻松的调用这个功能,详情参见Eclipse参见http://live.eclipse.org/node/723

     

     

    1.编译以下程序nonstop

     1 // gdb non-stop mode demo
     2 // build instruction: g++ -g -o nonstop nonstop.cpp -lboost_thread
     3 
     4 #include <iostream>
     5 #include <boost/thread/thread.hpp>
     6 
     7 struct op
     8 {
     9         op(int id): m_id(id) {}
    10 
    11         void operator()()
    12         {
    13                 std::cout << m_id << " begin" << std::endl;
    14                 std::cout << m_id << " end" << std::endl;
    15         }
    16 
    17         int m_id;
    18 };
    19 
    20 int main(int argc, char ** argv)
    21 {
    22         boost::thread t1(op(1)), t2(op(2)), t3(op(3));
    23         t1.join(); t2.join(); t3.join();
    24         return 0;
    25 }
    26 

     

    2.把一下3行添加到~/.gdbinit来打开non-stop模式

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

     

    3.启动gdb,设断点,运行.可以看到主线程1running,3个子线程都断在断点上,而不是只有一个子线程断在断点上.

    ~/devroot/nonstop$ gdb ./nonstop
    GNU gdb (GDB) 7.0-ubuntu
    Reading symbols from /home/frankwu/devroot/nonstop/nonstop...done.
    (gdb) break 14
    Breakpoint 1 at 0x402058: file nonstop.cpp, line 14.
    (gdb) break 24
    Breakpoint 3 at 0x401805: file nonstop.cpp, line 24.
    (gdb) run
    Starting program: /home/frankwu/devroot/nonstop/nonstop
    [Thread debugging using libthread_db enabled]
    [New Thread 0x7ffff6c89910 (LWP 2762)]
    [New Thread 0x7ffff6488910 (LWP 2763)]
    1 begin
    Breakpoint 1, op::operator() (this=0x605118) at nonstop.cpp:14
    14                  std::cout << m_id << " end" << std::endl
    ;
    2 begin
    Breakpoint 1, op::operator() (this=0x605388) at nonstop.cpp:14
    14                  std::cout << m_id << " end" << std::endl
    ;
    [New Thread 0x7ffff5c87910 (LWP 2764)]
    3 begin
    Breakpoint 1, op::operator() (this=0x605618) at nonstop.cpp:14
    14                  std::cout << m_id << " end" << std::endl
    ;
    (gdb) info threads
      4 Thread 0x7ffff5c87910 (LWP 2764)  op::operator() (this=0x605618) at nonstop.cpp:14
      3 Thread 0x7ffff6488910 (LWP 2763)  op::operator() (this=0x605388) at nonstop.cpp:14
      2 Thread 0x7ffff6c89910 (LWP 2762)  op::operator() (this=0x605118) at nonstop.cpp:14
    * 1 Thread 0x7ffff7fe3710 (LWP 2759)  (running)

     

    4.让线程3继续运行,注意我顾意把主线程1continue,这是我发现的workaround,否则gdb不能切回thread 1.

    (gdb) thread apply 3 1 continue

    Thread 3 (Thread 0x7ffff6488910 (LWP 2763)):
    Continuing.

    Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
    Continuing.
    Cannot execute this command while the selected thread is running.
    2 end
    [Thread 0x7ffff6488910 (LWP 2763) exited]

    warning: Unknown thread 3.

    Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
    Continuing.
    Cannot execute this command while the selected thread is running.
    (gdb) info threads
      4 Thread 0x7ffff5c87910 (LWP 2764)  op::operator() (this=0x605618) at nonstop.cpp:14
      2 Thread 0x7ffff6c89910 (LWP 2762)  op::operator() (this=0x605118) at nonstop.cpp:14
    * 1 Thread 0x7ffff7fe3710 (LWP 2759)  (running)

     

    5.让另外两个线程继续运行而结束,主线程断在第24,最后结束.

    (gdb) thread apply 4 2 1 continue

    Thread 4 (Thread 0x7ffff5c87910 (LWP 2764)):
    Continuing.

    Thread 2 (Thread 0x7ffff6c89910 (LWP 2762)):
    Continuing.

    Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
    Continuing.
    Cannot execute this command while the selected thread is running.
    3 end
    1 end
    [Thread 0x7ffff5c87910 (LWP 2764) exited]
    [Thread 0x7ffff6c89910 (LWP 2762) exited]

    Breakpoint 3, main (argc=1, argv=0x7fffffffe348) at nonstop.cpp:24
    24          return 0
    ;

    (gdb) continue
    Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
    Continuing.

    Program exited normally.

    参考资料

    Debugging with GDB 

    ReverseDebugging, Multi-Process and Non-Stop Debugging Come to the CDT 

     

0 0