当前位置: 首页 > news >正文

Valgrind的使用复习


1. 安装 Valgrind(包含 Helgrind)

在 Ubuntu 中安装 Valgrind:

sudo apt update
sudo apt install valgrind

2. 编写多线程测试代码

创建一个 C++ 程序 thread_example.cpp,模拟多线程数据竞争和死锁问题:

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx1, mtx2;
int shared_counter = 0;  // 共享变量(存在数据竞争)// 问题1:数据竞争(两个线程同时修改共享变量未加锁)
void race_condition() {for (int i = 0; i < 10000; ++i) {shared_counter++;  // 未加锁,导致数据竞争}
}// 问题2:死锁(两个线程以不同顺序获取锁)
void deadlock_thread1() {std::lock_guard<std::mutex> lock1(mtx1);std::this_thread::sleep_for(std::chrono::milliseconds(1));std::lock_guard<std::mutex> lock2(mtx2);  // 可能死锁
}void deadlock_thread2() {std::lock_guard<std::mutex> lock2(mtx2);std::this_thread::sleep_for(std::chrono::milliseconds(1));std::lock_guard<std::mutex> lock1(mtx1);  // 可能死锁
}int main() {// 数据竞争测试std::thread t1(race_condition);std::thread t2(race_condition);t1.join();t2.join();std::cout << "shared_counter = " << shared_counter << std::endl;// 死锁测试std::thread t3(deadlock_thread1);std::thread t4(deadlock_thread2);t3.join();t4.join();return 0;
}

3. 编译代码(添加调试信息)

使用 g++ 编译并链接多线程库 -pthread

g++ -g -pthread thread_example.cpp -o thread_example

4. 使用 Helgrind 检测多线程问题

运行 Helgrind 工具:

valgrind --tool=helgrind ./thread_example

5. 分析 Helgrind 输出

Helgrind 会报告以下关键问题:

1. 数据竞争(Race Condition)
==12345== Possible data race during write of size 4 at 0x12345678 by thread #1
==12345==    at 0x400D34: race_condition() (thread_example.cpp:11)
==12345==  This conflicts with a previous write by thread #2
==12345==    at 0x400D34: race_condition() (thread_example.cpp:11)
  • 原因:两个线程同时修改 shared_counter 未加锁,导致结果不可预测。
2. 死锁风险(Deadlock)
==12345==  Lock at 0x12345678 (mtx1) was first observed
==12345==    at 0x400E12: deadlock_thread1() (thread_example.cpp:16)
==12345==  Possible deadlock: inconsistent lock order detected
  • 原因t3t4 以不同顺序获取锁(mtx1mtx2),可能导致死锁。

6. 修复代码并重新验证

修复数据竞争

使用 std::mutex 保护共享变量:

void race_condition_fixed() {std::lock_guard<std::mutex> lock(mtx1);for (int i = 0; i < 10000; ++i) {shared_counter++;}
}
修复死锁

统一锁的获取顺序:

void deadlock_thread1_fixed() {std::lock(mtx1, mtx2);  // 同时获取两把锁,避免顺序问题std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
}void deadlock_thread2_fixed() {std::lock(mtx1, mtx2);  // 统一锁顺序std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
}
重新运行 Helgrind
g++ -g -pthread thread_example.cpp -o thread_example
valgrind --tool=helgrind ./thread_example

输出中不再报告数据竞争和死锁问题。


7. 高级用法

检测条件变量问题
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void wait_thread() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; });  // 正确使用条件变量
}void signal_thread() {std::lock_guard<std::mutex> lock(mtx);ready = true;cv.notify_one();
}

Helgrind 会检查条件变量的正确使用(如是否在持有锁时调用 notify)。


常见问题解决

  1. 误报问题

    • Helgrind 可能误报某些标准库操作(如 std::cout),可使用 --suppressions 过滤:
      valgrind --tool=helgrind --suppressions=/path/to/suppressions.txt ./thread_example
      
  2. 性能影响

    • Helgrind 会显著降低程序运行速度,建议仅在调试阶段使用。

总结

  • Helgrind 的核心功能:检测多线程问题(数据竞争、死锁、锁顺序问题)。
  • 关键步骤
    1. 使用 g++ -g -pthread 编译代码。
    2. 运行 valgrind --tool=helgrind
    3. 根据报告修复锁的使用或共享变量保护。
  • 最佳实践
    • 使用 std::lock_guardstd::unique_lock 自动管理锁。
    • 统一锁的获取顺序,避免死锁。
http://www.xdnf.cn/news/1153.html

相关文章:

  • 更换 CentOS 7.9 的系统源
  • 【软考-系统架构设计师】ATAM方法及效用树
  • 【python】pyCharm常用快捷键使用-(2)
  • C++入门基础:命名空间,缺省参数,函数重载,输入输出
  • blender 录课键位显示插件(图文傻瓜式安装)
  • .net core 项目快速接入Coze智能体-开箱即用-全局说明
  • 数据结构之BFS广度优先算法(腐烂的苹果)
  • ARINC818-1协议
  • visual Studio+Qt插件检查内存泄漏
  • Azure 私有端点和存储帐户用例
  • 基于springboot医药连锁店管理系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 【论文精读】COLMAP-Free 3D Gaussian Splatting
  • vue入门:路由 router
  • [GESP202409 二级] 小杨的 N 字矩阵 题解
  • 《如何用 Function 实现动态配置驱动的处理器注册机制?》
  • Ubuntu多用户VNC远程桌面环境搭建:从零开始的完整指南
  • 多路由器通过三层交换机互相通讯(单臂路由+静态路由+默认路由版),通过三层交换机让pc端相互通讯
  • C++之类模板
  • 定制化突围:遨游防爆手机的差异化竞争策略
  • 实战|使用环信Flutter SDK构建鸿蒙HarmonyOS应用及推送配置
  • vue MarkdownIt标签多出了<p>标签导致高度变丑
  • 前端路由缓存实现
  • ServletContextAttributeListener 的用法笔记250417
  • MYSQL “Too Many Connections“ 错误解决
  • 【Python入门】文件读取全攻略:5种常用格式(csv/excel/word/ppt/pdf)一键搞定 | 附完整代码示例
  • Java基础系列-LinkedList源码解析
  • Vue项目Webpack Loader全解析:从原理到实战配置指南
  • MYOJ_11700(UVA10591)Happy Number(快乐数)(超快解法:图论思想解题)
  • JVM考古现场(二十二):降维打击·用二向箔优化内存模型
  • android如何在生产环境中做到详实的日志收集而不影响性能?