Valgrind的多线程调试工具
Valgrind的多线程调试工具
Helgrind是Valgrind的一个重点功能 本节主要针对与多线程基本安全问题进行检测:【所有的代码环境都是在POSIX_THREAD模式下】
写线程代码时 经常碰到如下问题
1) 资源不安全访问 【就是多个线程在没有同步的情况下写某个资源体】
2) 死锁问题
3) POSIX pthreads API的错误使用
4) 在前面几个基础上都能安全无误的情况下 多于多线程程序就是要能够能好将同步块尽量缩到最小 【这是一个很大的课题】
解决问题:
问题1: 调用Helgrind能够很好的解决掉 已基本例子为例:
#include <pthread.h>
int var = 0;
void* child_fn ( void* arg ) {
var++;
return NULL;
}
int main ( void ) {
pthread_t child;
pthread_t child2;
pthread_create(&child,NULL, child_fn, NULL);
pthread_create(&child2,NULL,child_fn,NULL);
pthread_join(child,NULL);
pthread_join(child2,NULL);
return 0;
}
明显var是共享的 不安全访问,调用Helgrind看看怎么能够检测出来
gcc -g thread_helgrind.c -o thread_helgrind -lpthread
valgrind --tool=helgrind ./thread_helgrind
可以看出valgrind弹出如下输出信息:
==25516== Helgrind, a thread error detector
==25516== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==25516== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==25516== Command: ./thread_helgrind
==25516==
==25516== ---Thread-Announcement------------------------------------------
==25516==
==25516== Thread #3 was created
==25516== at 0x415B3C8: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516== ---Thread-Announcement------------------------------------------
==25516==
==25516== Thread #2 was created
==25516== at 0x415B3C8: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516== ----------------------------------------------------------------
==25516==
==25516== Possible data race during read of size 4 at 0x804A028 by thread #3
==25516== Locks held: none
==25516== at 0x804851F: child_fn (thread_helgrind.c:12)
==25516== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==25516== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==25516== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516== This conflicts with a previous write of size 4 by thread #2
==25516== Locks held: none
==25516== at 0x8048527: child_fn (thread_helgrind.c:12)
==25516== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==25516== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==25516== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516== ----------------------------------------------------------------
==25516==
==25516== Possible data race during write of size 4 at 0x804A028 by thread #3
==25516== Locks held: none
==25516== at 0x8048527: child_fn (thread_helgrind.c:12)
==25516== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==25516== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==25516== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516== This conflicts with a previous write of size 4 by thread #2
==25516== Locks held: none
==25516== at 0x8048527: child_fn (thread_helgrind.c:12)
==25516== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==25516== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==25516== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==25516==
==25516==
==25516== For counts of detected and suppressed errors, rerun with: -v
==25516== Use --history-level=approx or =none to gain increased speed, at
==25516== the cost of reduced accuracy of conflicting-access information
==25516== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
可以看出绿色就显示的data_race错误 可以直接定位到var前后没有locks/
问题2:
死锁问题是尽量避免 对于helgrind可以检测出加锁解锁顺序出现问题导致的死锁问题 这个问题我们可以好好看下:
首先 看下一个正常的程序
#include <pthread.h>
pthread_mutex_t mut_thread;
int var = 0;
void* child_fn ( void* arg ) {
pthread_mutex_lock(&mut_thread);
var++;
pthread_mutex_unlock(&mut_thread);
return NULL;
}
int main ( void ) {
pthread_t child;
pthread_t child2;
pthread_mutex_init(&mut_thread,NULL);
pthread_create(&child,NULL, child_fn, NULL);
pthread_create(&child2,NULL,child_fn,NULL);
pthread_join(child,NULL);
pthread_join(child2,NULL);
return 0;
}
正常加锁解锁 没有问题
在看下连续加2次锁的情况:
#include <pthread.h>
pthread_mutex_t mut_thread;
int var = 0;
void* child_fn ( void* arg ) {
pthread_mutex_lock(&mut_thread);
var++;
pthread_mutex_lock(&mut_thread);
return NULL;
}
int main ( void ) {
pthread_t child;
pthread_t child2;
pthread_mutex_init(&mut_thread,NULL);
pthread_create(&child,NULL, child_fn, NULL);
pthread_create(&child2,NULL,child_fn,NULL);
pthread_join(child,NULL);
pthread_join(child2,NULL);
return 0;
}
看下这个helgrind打印出来的东西 【当然要杀死 不然会一直卡在那里动都不动一下】
==26534== Helgrind, a thread error detector
==26534== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==26534== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==26534== Command: ./deadlock_helgrind
==26534==
==26534== ---Thread-Announcement------------------------------------------
==26534==
==26534== Thread #2 was created
==26534== at 0x415B3C8: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26534==
==26534== ----------------------------------------------------------------
==26534==
==26534== Thread #2: Attempt to re-lock a non-recursive lock I already hold
==26534== at 0x402E8E5: pthread_mutex_lock (hg_intercepts.c:507)
==26534== by 0x80485C6: child_fn (deadlock_helgrind.c:14)
==26534== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26534== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26534== Lock was previously acquired
==26534== at 0x402E95D: pthread_mutex_lock (hg_intercepts.c:518)
==26534== by 0x80485AD: child_fn (deadlock_helgrind.c:12)
==26534== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26534== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26534==
^C==26534== ----------------------------------------------------------------
==26534==
==26534== Thread #2: Exiting thread still holds 1 lock
==26534== at 0x4001182: ??? (in /lib/i386-linux-gnu/ld-2.17.so)
==26534== by 0x405B4D1: __lll_lock_wait (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x4056ED3: _L_lock_776 (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x4056D11: pthread_mutex_lock (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x402E914: pthread_mutex_lock (hg_intercepts.c:510)
==26534== by 0x80485C6: child_fn (deadlock_helgrind.c:14)
==26534== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26534== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26534== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26534==
==26534==
==26534== For counts of detected and suppressed errors, rerun with: -v
==26534== Use --history-level=approx or =none to gain increased speed, at
==26534== the cost of reduced accuracy of conflicting-access information
==26534== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0
Lock was previously acquired 对于自身线程来讲 这样的做法明显出问题 它自身还在尝试获取这个lock 这样就导致死锁的发生。可以定位到==26534== by 0x80485C6: child_fn (deadlock_helgrind.c:14)出问题了 所以这个helgrind解决这类问题时还是非常的厉害的~!
接下来看一个2 mutex导致的问题:
#include <pthread.h>
pthread_mutex_t mut_thread;
pthread_mutex_t mut_thread1;
int var = 0;
void* child_fn ( void* arg ) {
pthread_mutex_lock(&mut_thread);
pthread_mutex_lock(&mut_thread1);
var++;
pthread_mutex_unlock(&mut_thread);
pthread_mutex_unlock(&mut_thread1);
return NULL;
}
void* child_fn1(void *arg)
{
pthread_mutex_lock(&mut_thread1);
pthread_mutex_lock(&mut_thread);
var++;
pthread_mutex_unlock(&mut_thread1);
pthread_mutex_unlock(&mut_thread);
return NULL;
}
int main ( void ) {
pthread_t child;
pthread_t child2;
pthread_mutex_init(&mut_thread,NULL);
pthread_mutex_init(&mut_thread1,NULL);
pthread_create(&child,NULL, child_fn, NULL);
pthread_create(&child2,NULL,child_fn1,NULL);
pthread_join(child,NULL);
pthread_join(child2,NULL);
return 0;
}
加锁顺序导致死锁问题
==26785== Helgrind, a thread error detector
==26785== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==26785== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==26785== Command: ./deadlock_helgrind
==26785==
==26785== ---Thread-Announcement------------------------------------------
==26785==
==26785== Thread #3 was created
==26785== at 0x415B3C8: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26785==
==26785== ----------------------------------------------------------------
==26785==
==26785== Thread #3: lock order "0x804A038 before 0x804A050" violated
==26785==
==26785== Observed (incorrect) order is: acquisition of lock at 0x804A050
==26785== at 0x402E95D: pthread_mutex_lock (hg_intercepts.c:518)
==26785== by 0x8048637: child_fn1 (deadlock_helgrind.c:22)
==26785== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26785== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26785== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26785==
==26785== followed by a later acquisition of lock at 0x804A038
==26785== at 0x402E95D: pthread_mutex_lock (hg_intercepts.c:518)
==26785== by 0x8048643: child_fn1 (deadlock_helgrind.c:23)
==26785== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26785== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26785== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26785==
==26785== Required order was established by acquisition of lock at 0x804A038
==26785== at 0x402E95D: pthread_mutex_lock (hg_intercepts.c:518)
==26785== by 0x80485ED: child_fn (deadlock_helgrind.c:13)
==26785== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26785== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26785== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26785==
==26785== followed by a later acquisition of lock at 0x804A050
==26785== at 0x402E95D: pthread_mutex_lock (hg_intercepts.c:518)
==26785== by 0x80485F9: child_fn (deadlock_helgrind.c:14)
==26785== by 0x402E5F6: mythread_wrapper (hg_intercepts.c:233)
==26785== by 0x4054D77: start_thread (in /lib/i386-linux-gnu/libpthread-2.17.so)
==26785== by 0x415B3DD: clone (in /lib/i386-linux-gnu/libc-2.17.so)
==26785==
==26785==
==26785== For counts of detected and suppressed errors, rerun with: -v
==26785== Use --history-level=approx or =none to gain increased speed, at
==26785== the cost of reduced accuracy of conflicting-access information
==26785== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 9 from 9
这是观察法得出的 加锁顺序出错导致了这种情况的发生。
posix_thread erro这里就不列举了 这个完全是看基础。
下篇待续
Valgrind的多线程调试工具的更多相关文章
- Valgrind,内存调试工具
Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具 官网:http://valgrind.org/ 用户开发手册地址:http://valgrind.org/docs/manu ...
- http调试工具,linux调试工具
charles Linux下Web性能压力测试工具http_load linux 下的socket 调试工具 netcat Linux下四款Web服务器压力测试工具(http_load.webbenc ...
- 内存排查 valgrind
内存问题排查工具 --- valgrind 1. 概述 2. Valgrind 3. 内存泄漏监测 3.1. 示例代码 3.2. 编译它 3.3. 用Valgrind监测进程的内存泄漏 4. 悬挂指针 ...
- 内存问题排查工具 --- valgrind
1. 概述 2. Valgrind 3. 内存泄漏监测 3.1. 示例代码 3.2. 编译它 3.3. 用Valgrind监测进程的内存泄漏 4. 悬挂指针 4.1. 示例代码 4.2. Valgri ...
- FireFox VS Chrome 之 调试篇
一个完美的调试工具,FireBug! 精确跟踪每一步.仅仅要按下图所看到的,选择"脚本",然后在下方选择脚本所在的文件就可以对该文本的运行进行断点跟踪. 而且仅当一个线程运行结束后 ...
- C++内存泄漏检测工具
C++内存泄漏检测工具 1.VC自带的CRT:_CrtCheckMemory 调试器和 CRT 调试堆函数 1.1用法: /************************************ ...
- golang goroutine 介绍
Goroutine 是用户态自己实现的线程,调度方式遇到IO/阻塞点方式就会让出cpu时间(其实也看编译器的实现,如果TA在代码里面插入一些yield,也是可以的. 反正现在不是抢占式的.) 不能设置 ...
- iOS 10 的一个重要更新-线程竞态检测工具 Thread Sanitizer
本文介绍了 Xcode 8 的新出的多线程调试工具 Thread Sanitizer,可以在 app 运行时发现线程竞态. 想想一下,你的 app 已经近乎大功告成:它经过精良的打磨,单元测试全覆盖. ...
- valgrind 打印程序调用树+进行多线程性能分析
使用valgrind的callgrind工具进行多线程性能分析 yum install valgrind / wget http://valgrind.org/downloads/valgrind-3 ...
随机推荐
- Fiddler—PC上实现手机的抓包
PC上安装Fiddler之后,可以抓取各种浏览器的请求,通过一些设置可以获取iPhone.安卓手机.windows phone的请求.具体的工作原理我也不多说(哼,绝对不是因为我不懂XD),主要说下如 ...
- 【入门】匈牙利算法+HNOI2006 hero超级英雄
一.关于匈牙利算法 匈牙利算法是由匈牙利数学家Edmonds提出的,用增广路径求二分图最大匹配的算法. 听起来高端,其实说白了就是: 假设不存在单相思(单身狗偷偷抹眼泪),在一个同性恋不合法的国家里( ...
- R----lubridata包介绍学习
lubridate包,非常强大,能够识别各种类型的日期.字符型和时间型数据,都是格式比较特别的你数据,在处理时,比较麻烦,但是有了lubridate这个包之后,时间处理变得非常简单,这个包函数命名简单 ...
- 深入对比数据科学工具箱:Python和R之争
建议:如果只是处理(小)数据的,用R.结果更可靠,速度可以接受,上手方便,多有现成的命令.程序可以用.要自己搞个算法.处理大数据.计算量大的,用python.开发效率高,一切尽在掌握. 概述 在真实的 ...
- FIFO页面置换算法
本文以序列长度20的{ 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1};以及页面4:为例: #include <stdio.h> #define Init ...
- Code First Migrations更新数据库结构(数据迁移)
背景 code first起初当修改model后,要持久化至数据库中时,总要把原数据库给删除掉再创建 (DropCreateDatabaseIfModelChanges),此时就会产生一个问题,当我们 ...
- 高宽不定的div相对父div上下、左右居中
<div class="parent"> <div class="child">123</div> </div> ...
- 页面加载后resize页面布局
在我们写web的时候,有的时候页面加载完以后,布局位置有一些问题,手动改变窗口大小后则正常显示位置. 其实,我们手动改变窗口大小,是执行了resize方法. share一下兼容方法: coffee c ...
- contiki-main.c 文件的进程分析
基本进程的创建实例: 共三部分:创建进程.进程自启动和进程的主体部分 /* 声明一个名为hello_world_process和led_process进程 PROCESS 宏实际上声明一个函数并定义一 ...
- j.一个NIO与SSLEngine结合的例子
对于BIO通道的程序来讲,建立起SSLServerSocket之后,后续的工作就和普通的ServerSocket没有什么区别了,这是因为JDK中通过JSSE的API,封装了SSL通道的实现逻辑,否则, ...