数据竞争(data race)问题分析的利器——valgrind的Helgrind
时间:2022-06-17
本文章向大家介绍数据竞争(data race)问题分析的利器——valgrind的Helgrind,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
数据竞争(data race)是指在非线程安全的情况下,多线程对同一个地址空间进行写操作。一般来说,我们都会通过线程同步方法来保证数据的安全,比如采用互斥量或者读写锁。但是由于某些笔误或者设计的缺陷,还是存在data race的可能性的。(转载请指明出于breaksoftware的csdn博客)
比如下面这段代码
#define _GNU_SOURCE 1
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static pthread_rwlock_t s_rwlock;
static int s_racy;
static void sleep_ms(const int ms) {
struct timespec delay = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&delay, 0);
}
static void* thread_func(void* arg) {
pthread_rwlock_rdlock(&s_rwlock);
s_racy++;
pthread_rwlock_unlock(&s_rwlock);
sleep_ms(100);
return 0;
}
int main(int argc, char** argv) {
pthread_t thread1;
pthread_t thread2;
pthread_rwlock_init(&s_rwlock, 0);
pthread_create(&thread1, 0, thread_func, 0);
pthread_create(&thread2, 0, thread_func, 0);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
pthread_rwlock_destroy(&s_rwlock);
fprintf(stderr, "Result: %dn", s_racy);
return 0;
}
线程函数thread_fun主要工作就是对全局变量s_racy进行自增。由于自增是写操作,所以需要加锁。但是第16行加的是读锁——共享锁,这就意味着其他线程也会获得该读锁。这个错误就将导致两个线程同时无协调的修改s_racy变量。
对这个问题,我们可以使用如下指令分析
valgrind --tool=helgrind ./rdlock_race
最后我们会得到如下的结果显示
==5457== Possible data race during write of size 4 at 0x309078 by thread #3
==5457== Locks held: none
==5457== at 0x108A19: thread_func (rwlock_race.c:25)
==5457== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5457== by 0x4E496DA: start_thread (pthread_create.c:463)
==5457== by 0x518288E: clone (clone.S:95)
==5457==
==5457== This conflicts with a previous write of size 4 by thread #2
==5457== Locks held: none
==5457== at 0x108A19: thread_func (rwlock_race.c:25)
==5457== by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5457== by 0x4E496DA: start_thread (pthread_create.c:463)
==5457== by 0x518288E: clone (clone.S:95)
==5457== Address 0x309078 is 0 bytes inside data symbol "s_racy"
==5457==
第1行显示线程3访问的0x309078地址有4个字节空间可能存在数据竞争。
第2行显示线程3操作这个空间时没有持有独占锁。其具体操作的调用堆栈在第3到第6行体现。
第8行显示线程2也操作了这个空间。
第9行显示线程2操作这个空间是也没有持有独占锁。
第14行则直接指出被操作的空间的变量名称为s_racy。
如此我们便找到存在数据竞争的变量了。
我们将读锁改成写锁——即将pthread_rwlock_rdlock改成pthread_rwlock_wrlock,就不会出现上述分析结果了。
- 智能主题检测与无监督机器学习:识别颜色教程
- 如何下载安装Weka机器学习工作平台
- Dubbo 源码解析 —— LoadBalance
- 如何处理机器学习中类的不平衡问题
- 【死磕Java并发】—– Java内存模型之重排序
- Mask R-CNN源代码终于来了,还有它背后的物体检测平台
- 37个TOP实例命令,超过一半你肯定都没见过
- 利用TensorFlow生成图像标题
- 保存并加载您的Keras深度学习模型
- 简单、通用的JQuery Tab实现
- Dubbo源码解析 - 远程暴露
- 使用FastText(Facebook的NLP库)进行文本分类和word representatio...
- 声音分类的迁移学习
- 【死磕Java并发】—– J.U.C之AQS:CLH同步队列
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 5 个 JS 数组技巧可提高你的开发技能
- 一个有意思的方案:不借助后台和 JS ,只用 CSS 让一个列表编号倒序,你会怎么做?
- 关于MySQL LOAD DATA特性的利用与思考
- NHibernate 缓存
- 渗透测试 | 突破前端JS加密限制
- 使用 Task 简化异步编程
- Task 编程中的异常处理
- AngularJS 中的 factory、 service 和 provider
- 设计模式之适配器模式
- 设计模式之组合模式
- MvvmCross 框架中的数据绑定语法
- Vivado IP核锁定的解除方法
- Flutter Dojo设计之道——骚气的闪屏动画是如何实现的
- 数据处理 | pandas入门专题——离散化与one-hot
- 聊聊dubbo-go的failfastCluster