多线程调试必杀技 - GDB的non-stop模式

2023-10-10 07:48

本文主要是介绍多线程调试必杀技 - GDB的non-stop模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

作者:破砂锅

开源的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. #include <iostream>
  4. #include <boost/thread/thread.hpp>
  5. struct op
  6. {
  7. op(int id): m_id(id) {}
  8. void operator()()
  9. {
  10. std::cout << m_id << " begin" << std::endl;
  11. std::cout << m_id << " end" << std::endl;
  12. }
  13. int m_id;
  14. };
  15. int main(int argc, char ** argv)
  16. {
  17. boost::thread t1(op(1)), t2(op(2)), t3(op(3));
  18. t1.join(); t2.join(); t3.join();
  19. return 0;
  20. }

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

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

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

      
  1. ~/devroot/nonstop$ gdb ./nonstop
  2. GNU gdb (GDB) 7.0-ubuntu
  3. Reading symbols from /home/frankwu/devroot/nonstop/nonstop...done.
  4. (gdb) break 14
  5. Breakpoint 1 at 0x402058: file nonstop.cpp, line 14.
  6. (gdb) break 24
  7. Breakpoint 3 at 0x401805: file nonstop.cpp, line 24.
  8. (gdb) run
  9. Starting program: /home/frankwu/devroot/nonstop/nonstop
  10. [Thread debugging using libthread_db enabled]
  11. [New Thread 0x7ffff6c89910 (LWP 2762)]
  12. [New Thread 0x7ffff6488910 (LWP 2763)]
  13. begin
  14. Breakpoint 1, op::operator() (this=0x605118) at nonstop.cpp:14
  15. std::cout << m_id << " end" << std::endl;
  16. begin
  17. Breakpoint 1, op::operator() (this=0x605388) at nonstop.cpp:14
  18. std::cout << m_id << " end" << std::endl;
  19. [New Thread 0x7ffff5c87910 (LWP 2764)]
  20. begin
  21. Breakpoint 1, op::operator() (this=0x605618) at nonstop.cpp:14
  22. std::cout << m_id << " end" << std::endl;
  23. (gdb) info threads
  24. Thread 0x7ffff5c87910 (LWP 2764) op::operator() (this=0x605618) at nonstop.cpp:14
  25. Thread 0x7ffff6488910 (LWP 2763) op::operator() (this=0x605388) at nonstop.cpp:14
  26. Thread 0x7ffff6c89910 (LWP 2762) op::operator() (this=0x605118) at nonstop.cpp:14
  27. * 1 Thread 0x7ffff7fe3710 (LWP 2759) (running)

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

      
  1. (gdb) thread apply 3 1 continue
  2. Thread 3 (Thread 0x7ffff6488910 (LWP 2763)):
  3. Continuing.
  4. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
  5. Continuing.
  6. Cannot execute this command while the selected thread is running.
  7. end
  8. [Thread 0x7ffff6488910 (LWP 2763) exited]
  9. warning: Unknown thread 3.
  10. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
  11. Continuing.
  12. Cannot execute this command while the selected thread is running.
  13. (gdb) info threads
  14. Thread 0x7ffff5c87910 (LWP 2764) op::operator() (this=0x605618) at nonstop.cpp:14
  15. Thread 0x7ffff6c89910 (LWP 2762) op::operator() (this=0x605118) at nonstop.cpp:14
  16. * 1 Thread 0x7ffff7fe3710 (LWP 2759) (running)

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

      
  1. (gdb) thread apply 4 2 1 continue
  2. Thread 4 (Thread 0x7ffff5c87910 (LWP 2764)):
  3. Continuing.
  4. Thread 2 (Thread 0x7ffff6c89910 (LWP 2762)):
  5. Continuing.
  6. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
  7. Continuing.
  8. Cannot execute this command while the selected thread is running.
  9. end
  10. end
  11. [Thread 0x7ffff5c87910 (LWP 2764) exited]
  12. [Thread 0x7ffff6c89910 (LWP 2762) exited]
  13. Breakpoint 3, main (argc=1, argv=0x7fffffffe348) at nonstop.cpp:24
  14. return 0;
  15. (gdb) continue
  16. Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
  17. Continuing.
  18. Program exited normally.

参考资料

Debugging with GDB

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

(破砂锅 )

这篇关于多线程调试必杀技 - GDB的non-stop模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/179048

相关文章

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

在IntelliJ IDEA中高效运行与调试Spring Boot项目的实战步骤

《在IntelliJIDEA中高效运行与调试SpringBoot项目的实战步骤》本章详解SpringBoot项目导入IntelliJIDEA的流程,教授运行与调试技巧,包括断点设置与变量查看,奠定... 目录引言:为良驹配上好鞍一、为何选择IntelliJ IDEA?二、实战:导入并运行你的第一个项目步骤1