第9课:GDB 实用调试技巧(下)
本节课的核心内容多线程下禁止线程切换条件断点使用 GDB 调试多进程程序10.1 多线程下禁止线程切换假设现在有 5 个线程除了主线程工作线程都是下面这样的一个函数void thread_proc(void* arg) { //代码行1 //代码行2 //代码行3 //代码行4 //代码行5 //代码行6 //代码行7 //代码行8 //代码行9 //代码行10 //代码行11 //代码行12 //代码行13 //代码行14 //代码行15 }为了能说清楚这个问题我们把四个工作线程分别叫做 A、B、C、D。假设 GDB 当前正在处于线程 A 的代码行 3 处此时输入 next 命令我们期望的是调试器跳到代码行 4 处或者使用“u 代码行10”那么我们期望输入 u 命令后调试器可以跳转到代码行 10 处。但是在实际情况下GDB 可能会跳转到代码行 1 或者代码行 2 处甚至代码行 13、代码行 14 这样的地方也是有可能的这不是调试器 bug这是多线程程序的特点当我们从代码行 4 处让程序 continue 时线程 A 虽然会继续往下执行但是如果此时系统的线程调度将 CPU 时间片切换到线程 B、C 或者 D 呢那么程序最终停下来的时候处于代码行 1 或者代码行 2 或者其他地方就不奇怪了而此时打印相关的变量值可能就不是我们需要的线程 A 的相关值。为了解决调试多线程程序时出现的这种问题GDB 提供了一个在调试时将程序执行流锁定在当前调试线程的命令set scheduler-locking on。当然也可以关闭这一选项使用 set scheduler-locking off。除了 on/off 这两个值选项还有一个不太常用的值叫 step这里就不介绍了。10.2 条件断点在实际调试中我们一般会用到三种断点普通断点、条件断点和硬件断点。硬件断点又叫数据断点这样的断点其实就是前面课程中介绍的用 watch 命令添加的部分断点为什么是部分而不是全部前面介绍原因了watch 添加的断点有部分是通过软中断实现的不属于硬件断点。硬件断点的触发时机是监视的内存地址或者变量值发生变化。普通断点就是除去条件断点和硬件断点以外的断点。下面重点来介绍一下条件断点所谓条件断点就是满足某个条件才会触发的断点这里先举一个直观的例子void do_something_func(int i) { i ; i 100 * i; } int main() { for(int i 0; i 10000; i) { do_something_func(i); } return 0; }在上述代码中假如我们希望当变量 i5000 时进入 do_something_func() 函数追踪一下这个函数的执行细节。此时可以修改代码增加一个 i5000 的 if 条件然后重新编译链接调试这样显然比较麻烦尤其是对于一些大型项目每次重新编译链接都需要花一定的时间而且调试完了还得把程序修改回来。有了条件断点就不需要这么麻烦了添加条件断点的命令是 break [lineNo] if [condition]其中 lineNo 是程序触发断点后需要停下的位置condition 是断点触发的条件。这里可以写成 break 11 if i5000其中11 就是调用 do_something_fun() 函数所在的行号。当然这里的行号必须是合理行号如果行号非法或者行号位置不合理也不会触发这个断点。(gdb) break 11 if i5000 Breakpoint 2 at 0x400514: file test1.c, line 10. (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/testgdb/test1 Breakpoint 1, main () at test1.c:9 9 for(int i 0; i 10000; i) (gdb) c Continuing. Breakpoint 2, main () at test1.c:11 11 do_something_func(i); (gdb) p i $1 5000把 i 打印出来GDB 确实是在 i5000 时停下来了。添加条件断点还有一个方法就是先添加一个普通断点然后使用“condition 断点编号断点触发条件”这样的方式来添加。添加一下上述断点(gdb) b 11 Breakpoint 1 at 0x400514: file test1.c, line 11. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x0000000000400514 in main at test1.c:11 (gdb) condition 1 i5000 (gdb) r Starting program: /root/testgdb/test1 y Breakpoint 1, main () at test1.c:11 11 do_something_func(i); Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.el7_4.2.x86_64 (gdb) p i $1 5000 (gdb)同样的规则如果断点编号不存在也无法添加成功GDB 会提示断点不存在(gdb) condition 2 i5000 No breakpoint number 2.10.3 使用 GDB 调试多进程程序这里说的多进程程序指的是一个进程使用 Linux 系统调用 fork() 函数产生的子进程没有相互关联的进程就是普通的 GDB 调试不必刻意讨论。在实际的应用中如有这样一类程序如 Nginx对于客户端的连接是采用多进程模型当 Nginx 接受客户端连接后创建一个新的进程来处理这一路连接上的信息来往新产生的进程与原进程互为父子关系那么如何用 GDB 调试这样的父子进程呢一般有两种方法用 GDB 先调试父进程等子进程 fork 出来后使用 gdb attach 到子进程上去当然这需要重新开启一个 session 窗口用于调试gdb attach 的用法在前面已经介绍过了GDB 调试器提供了一个选项叫 follow-fork可以使用 show follow-fork mode 查看当前值也可以通过 set follow-fork mode 来设置是当一个进程 fork 出新的子进程时GDB 是继续调试父进程还是子进程取值是 child默认是父进程 取值是 parent。(gdb) show follow-fork mode Debugger response to a program call of fork or vfork is parent. (gdb) set follow-fork child (gdb) show follow-fork mode Debugger response to a program call of fork or vfork is child. (gdb)建议读者自己写个程序然后调用 fork() 函数去实践一下若要想阅读和调试 Apache HTTP Server 或者 Nginx 这样的程序这个技能是必须要掌握的。

相关新闻

Java开发者必看:从HttpClient到Spring AI,大模型应用开发全攻略!

Java开发者必看:从HttpClient到Spring AI,大模型应用开发全攻略!

一、从基础开始:用HttpClient直接调用大模型 在Java中调用大模型,最直接、最简单的方式是什么? 没错,就是使用HTTP客户端。因为大模型通常都提供了RESTful API,我们可以直接通过发送HTTP请求来调用它们。 我们以阿里…

2026/6/28 3:18:16阅读更多 →
设计模式之策略模式Python实现

设计模式之策略模式Python实现

一、引言 在软件开发中,我们经常会遇到这样的场景:一个业务逻辑需要根据不同的情况采用不同的算法或行为。例如,电商系统中根据用户等级计算折扣、文件压缩时选择不同的压缩算法、支付时选择不同的支付渠道…… 如果将这些算法硬编码在同一个类中,不仅会导致类庞大臃肿,还…

2026/6/28 3:13:16阅读更多 →
【开源】尖叫,AI从椅子上站起来告诉你什么是真正的天下报表-自已定义模板自适应PC手机

【开源】尖叫,AI从椅子上站起来告诉你什么是真正的天下报表-自已定义模板自适应PC手机

【开源】尖叫,AI从椅子上站起来告诉你什么是真正的天下报表-自已定义模板自适应PC手机 作者:csdn 咏方舟-长江支流 2026-06-27 我给AI投喂了2014年写的XML配置的报表在VS2019迁移到Asp.Net Core3时的设计文档(里面包含了接口及重要接口和基…

2026/6/28 3:13:16阅读更多 →
Akagi:三步搭建你的专属免费麻将AI助手,实时分析提升牌技

Akagi:三步搭建你的专属免费麻将AI助手,实时分析提升牌技

Akagi:三步搭建你的专属免费麻将AI助手,实时分析提升牌技 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將,能夠使用自定義的AI模型實時分析對局並給出建議,內建Mortal AI作為示例。 Supports Majsoul, Tenhou, Riic…

2026/6/28 6:38:27阅读更多 →
UEFI基础实践1:环境搭建

UEFI基础实践1:环境搭建

目录 1、Windows环境下搭建UEFI开发环境 1、安装开发工具 2、下载EDK2开发包和其他必要开发包 3、开发环境配置 3.1、更新submodule 3.2、编译BaseTool 3.3、设置开发工具路径 3.4、检查edk2/Conf配置文件 4、编译UEFI模拟器和UEFI程序 4.1、编译UEFI模拟器 4.2、编…

2026/6/28 6:38:27阅读更多 →
Cocos Creator可玩广告打包终极指南:3步生成单HTML文件

Cocos Creator可玩广告打包终极指南:3步生成单HTML文件

Cocos Creator可玩广告打包终极指南:3步生成单HTML文件 【免费下载链接】cocos-to-playable-ad 将 cocos creator 构建出来的 web-mobile 项目打包为 playable-ad 项目,即单 html 文件。 项目地址: https://gitcode.com/gh_mirrors/co/cocos-to-playab…

2026/6/28 6:38:27阅读更多 →
嵌入式高手都在偷偷用的“第6条”:两个符号 # 和 ## ,让编译器帮你拼出寄存器名和变量名

嵌入式高手都在偷偷用的“第6条”:两个符号 # 和 ## ,让编译器帮你拼出寄存器名和变量名

该文章同步至OneChan 你有没有经历过:需要访问一串编号连续的寄存器,比如 TIM2->CCR1、TIM2->CCR2……明知道名字规律明显,却只能一个一个手写,改一处就得全部重敲一遍? 这是资深工程师压箱底的编程技巧系列第六…

2026/6/28 6:38:27阅读更多 →
基于物联网设计的土壤多参数智能监测系统_427

基于物联网设计的土壤多参数智能监测系统_427

文章目录 一、前言 1.1 项目介绍 【1】项目开发背景 【2】设计实现的功能 【3】项目硬件模块组成 【4】设计意义 【5】国内外研究现状 国内研究现状 国外研究现状 技术发展趋势比较 【6】摘要 1.2 设计思路 1.3 系统功能总结 1.4 开发工具的选择 1.5 参考文献 1.6 系统框架图 1…

2026/6/28 6:38:27阅读更多 →
dp动态规划 0-1背包

dp动态规划 0-1背包

0-1 knapsack Problem 问题背景 超市赢家商品价格体积🍺 啤酒2410🧃 汽水23🍪 饼干94🍞 面包105🥛 牛奶94超市允许顾客使用一个体积大小为13的背包,选择一件或多件商品带走如何带走总价最多的商品 input&am…

2026/6/28 6:33:27阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/6/28 0:08:01阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/6/28 0:08:01阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/6/28 0:08:01阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/6/28 0:08:01阅读更多 →