作者:破砂锅  (转)

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

多线程调试之痛

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

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

  • 当某个或多个线程断在一个断点上,其他线程仍会并行运行
  • 你可以选择某个被断的线程,并让它继续运行

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

  • 当其他线程断在断点上时,程序里的定时器线程可以正常的运行了,从而避免不必要得超时
  • 当其他线程断在断点上时,程序里的watchdog线程可以正常的运行了,从而避免嵌入式硬件以为系统崩溃而重启
  • 可以控制多个线程运行的顺序,从而重现deadlock场景了。由于GDB可以用python脚本驱动调试,理论上可以对程序在不同的线程运行顺序下进行自动化测试。

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

演示GDB的non-stop模式

让破砂锅用一个C++小程序在Ubuntu Linux  09.10下demo这个必杀技。虽然我的demo使用命令行版gdb,如果你喜欢图形化的调试器,Eclipse2009年5月之后的版本可以轻松的调 用这个功能,详情参见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,设断点,运行.可以看到主线程1是running,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继续运行,注意我顾意把主线程1也continue,这是我发现的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

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

多线程调试必杀技 - GDB的non-stop模式的更多相关文章

  1. GDB 多线程调试:只停止断点的线程,其他线程任然执行; 或只运行某些线程 其他线程中断

    多线程调试之痛 调试器(如VS2008和老版GDB)往往只支持all-stop模式,调试多线程程序时,如果某个线程断在一个断点上,你的调试器会让整个程序freeze,直到你continue这个线程,程 ...

  2. [转] linux下的c/c++调试器gdb

    PS:1. 断点C++类函数,用b 命名空间::类名::方法名 2. 编译参数一定要加-g,才可断点调试 http://www.cnblogs.com/xd502djj/archive/2012/08 ...

  3. linux下的c/c++调试器gdb

    Reference:  http://www.cnblogs.com/xd502djj/archive/2012/08/30/2663960.html linux下的c/c++调试器gdb gdbLi ...

  4. [skill][gdb] gdb 多线程调试

    中文快速入门: http://coolshell.cn/articles/3643.html (关于多线程的部署说的并不太对) 进阶: 多进程相关概念: inferiors 是什么? http://m ...

  5. GDB常用调试命令以及多进程多线程调试

    http://blog.csdn.net/freeelinux/article/details/53700266 一:普通命令   1.list命令 list  linenum      显示程序第l ...

  6. gdb 多线程调试

    gdb 多线程调试 http://hi.baidu.com/hcq11/blog/item/9f5bfc6e696209d680cb4a25.html  http://hi.baidu.com/lit ...

  7. GDB多线程调试

    一.多线程调试1. 多线程调试,最重要的几个命令:info threads                        查看当前进程的线程.                              ...

  8. Linux系统编程@多线程与多进程GDB调试

    博客内容参考自 http://www.cnblogs.com/xuxm2007/archive/2011/04/01/2002162.html http://blog.csdn.net/pbymw8i ...

  9. 利用GDB进行多线程调试

    一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...

随机推荐

  1. Oracle JDeveloper 10g 卡顿、花屏的解决方法

    1.JDeveloper 10g花屏的解决办法: 在Win7或WinXP环境下,JDeveloper10g可能产生花屏现象,给开发者造成困扰,解决方法如下: 打开{JDEV_HOME}\jdev\bi ...

  2. 云计算IaaS浅谈

    (本篇文章仅仅是整理文档资料时,发现的一篇课程报告,感觉还挺有参考意义的) 最近几年云计算一直是IT业的热点,一股炽热的云计算浪潮席卷了世界,全世界都在讲云计算,都在搞云计算.虽然最初是由谷歌公司提出 ...

  3. 2016-2017-2 20155309 南皓芯《java程序设计》第八周学习总结

    教材学习内容总结 本周学习的主要是第十四章,第十五章的内容. NIO与NIO2 同步非阻塞IO(Java NIO) : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多 ...

  4. PowerTool x64驱动模块逆向分析(持续更新)

    比赛打完了,来继续搞了,因为那个主动防御正在写,所以想找找思路正好想到可以来逆向一下PT的驱动模块看看pt大大是怎么写的程序. PT x64版本的驱动模块是这个kEvP64.sys. 0x0 先来看看 ...

  5. CCF CSP 201312-4 有趣的数

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201312-4 有趣的数 问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0 ...

  6. UVA 10559 Blocks(区间DP&&递推)

    题目大意:给你玩一个一维版的消灭星星,得分是当前消去的区间的长度的平方,求最大得分. 现在分析一下题目 因为得分是长度的平方,不能直接累加,所以在计算得分时需要考虑前一个状态所消去的长度,仅用dp[l ...

  7. jenkins备份与恢复

    jenkins这里我通过thinbackup插件进行对jenkins的配置备份与恢复 1丶安装thinbackup插件 2丶系统管理选择thinbackup插件 3丶创建备份目录 mkdir /bac ...

  8. RabbitMQ错误检查

    今天使用RabbitMQ做数据下发操作,当在发送端声明了Exchange后 打开RabbitMQ的管理控制台,可以查看,其中已经创建了Exchange 但并没有Queue 接着运行接收端,发现以下错误 ...

  9. SQL Server 跨服务器快速数据转移

    最近遇到一个问题,要将 a 服务器上的 A 库,迁移到 b 服务器上的 B 库,两个库的数据结构是一样的,但是数据库版本是 a 比 b 高,通过 sqlserver  还原这条路是走不通了,那难道除了 ...

  10. 深入理解SQL的四种连接,左外连接,右外连接,内连接,全连接

    1.内联接(典型的联接运算,使用像 =  或 <> 之类的比较运算符).包括相等联接和自然联接.     内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行.例如,检索 stude ...