在《DllMain中不当操作导致死锁问题的分析--死锁介绍》一文中,我们介绍了死锁产生的原因。一般来说,如果我们对线程同步技术掌握不牢,或者同步方案混乱,极容易导致死锁。本文我们将介绍如何使用valgrind排查死锁问题。(转载请指明出于breaksoftware的csdn博客)

构造一个场景

#include <pthread.h>pthread_mutex_t s_mutex_a;
pthread_mutex_t s_mutex_b;
pthread_barrier_t s_barrier;void lock() {pthread_mutex_lock(&s_mutex_b);{pthread_barrier_wait(&s_barrier);pthread_mutex_lock(&s_mutex_a);pthread_mutex_unlock(&s_mutex_a);}pthread_mutex_unlock(&s_mutex_b);
}static void* thread_routine(void* arg) {pthread_mutex_lock(&s_mutex_a);{pthread_barrier_wait(&s_barrier);pthread_mutex_lock(&s_mutex_b);pthread_mutex_unlock(&s_mutex_b);}pthread_mutex_unlock(&s_mutex_a);
}int main(int argc, char** argv) {pthread_t tid;pthread_mutex_init(&s_mutex_a, 0);pthread_mutex_init(&s_mutex_b, 0);pthread_barrier_init(&s_barrier, 0, 2);pthread_create(&tid, 0, &thread_routine, 0);lock();pthread_join(tid, 0);pthread_cancel(tid);pthread_barrier_destroy(&s_barrier);pthread_mutex_destroy(&s_mutex_a);pthread_mutex_destroy(&s_mutex_b);return 0;
}

这段代码我们只要关注lock和thread_routine两个方法。

lock方法在主线程中执行,它先给s_mutex_b上锁,然后通过屏障s_barrier等待线程也执行到屏障处(第21行)。

thread_routine是线程函数,它先给s_mutex_a上锁,然后通过屏障s_barrier等待主线程也执行到屏障处(第10行)。

主线程和子线程都执行到屏障处后,屏障被打开,它们继续向下执行:主线程执行到第12行试图获取s_mutex_a;子线程执行到第23行试图获取s_mutex_b。由于这两个互斥量已经被占用,所以产生死锁。

这是通过代码分析出来的,但是对于比较大的工程项目,我们则需要通过工具来分析。下面我们使用valgrind来分析

valgrind --tool=drd --trace-mutex=yes ./dead_lock

我们使用上面指令,让valgrind把互斥量相关的信息给打印出来

==4749== [1] mutex_init      mutex 0x30a040
==4749== [1] mutex_init      mutex 0x30a0a0
==4749== [1] mutex_init      mutex 0x1ffefffe10
==4749== [1] mutex_ignore_ordering mutex 0x1ffefffe10
==4749== [1] mutex_trylock   mutex 0x1ffefffe10 rc 0 owner 0
==4749== [1] post_mutex_lock mutex 0x1ffefffe10 rc 0 owner 0
==4749== [1] mutex_unlock    mutex 0x1ffefffe10 rc 1
==4749== [2] mutex_trylock   mutex 0x1ffefffe10 rc 0 owner 1
==4749== [2] post_mutex_lock mutex 0x1ffefffe10 rc 0 owner 1
==4749== [2] mutex_unlock    mutex 0x1ffefffe10 rc 1
==4749== [2] mutex_trylock   mutex 0x30a040 rc 0 owner 0
==4749== [2] post_mutex_lock mutex 0x30a040 rc 0 owner 0
==4749== [1] cond_post_wait  mutex 0x1ffefffe10 rc 0 owner 2
==4749== [1] mutex_unlock    mutex 0x1ffefffe10 rc 1
==4749== [1] mutex_destroy   mutex 0x1ffefffe10 rc 0 owner 1
==4749== [1] mutex_trylock   mutex 0x30a0a0 rc 0 owner 0
==4749== [1] post_mutex_lock mutex 0x30a0a0 rc 0 owner 0
==4749== [1] mutex_trylock   mutex 0x30a040 rc 1 owner 2
==4749== [2] mutex_trylock   mutex 0x30a0a0 rc 1 owner 1

第18行显示线程1试图给0x30a040互斥量上锁,但是该互斥量的所有者(owner)是线程2。

第19行显示线程2试图给0x30a0a0互斥量上锁,但是该互斥量的所有者(owner)是线程1。

如此我们便可以确定这段程序卡住是因为死锁导致的。

但是DRD有个问题,不能指出发生死锁的位置。这个时候Helgrind该出场了。

valgrind --tool=helgrind ./dead_lock 

helgrind执行时,如果发生死锁,需要ctrl+C来终止运行,于是可以得到如下结果

==5373== Process terminating with default action of signal 2 (SIGINT)
==5373==    at 0x4E5310D: __lll_lock_wait (lowlevellock.S:135)
==5373==    by 0x4E4C022: pthread_mutex_lock (pthread_mutex_lock.c:78)
==5373==    by 0x4C33FD6: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5373==    by 0x108A11: lock (dead_lock.c:12)
==5373==    by 0x108AF4: main (dead_lock.c:38)
==5373== ---Thread-Announcement------------------------------------------
==5373==
==5373== Thread #2 was created
==5373==    at 0x518287E: clone (clone.S:71)
==5373==    by 0x4E49EC4: create_thread (createthread.c:100)
==5373==    by 0x4E49EC4: pthread_create@@GLIBC_2.2.5 (pthread_create.c:797)
==5373==    by 0x4C36A27: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5373==    by 0x108AEA: main (dead_lock.c:36)
==5373==
==5373== ----------------------------------------------------------------
==5373==
==5373== Thread #2: Exiting thread still holds 1 lock
==5373==    at 0x4E5310D: __lll_lock_wait (lowlevellock.S:135)
==5373==    by 0x4E4C022: pthread_mutex_lock (pthread_mutex_lock.c:78)
==5373==    by 0x4C33FD6: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5373==    by 0x108A5C: thread_routine (dead_lock.c:23)
==5373==    by 0x4C36C26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5373==    by 0x4E496DA: start_thread (pthread_create.c:463)
==5373==    by 0x518288E: clone (clone.S:95)
==5373==
==5373== ---Thread-Announcement------------------------------------------
==5373==
==5373== Thread #1 is the program's root thread
==5373==
==5373== ----------------------------------------------------------------
==5373==
==5373== Thread #1: Exiting thread still holds 1 lock
==5373==    at 0x4E5310D: __lll_lock_wait (lowlevellock.S:135)
==5373==    by 0x4E4C022: pthread_mutex_lock (pthread_mutex_lock.c:78)
==5373==    by 0x4C33FD6: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5373==    by 0x108A11: lock (dead_lock.c:12)
==5373==    by 0x108AF4: main (dead_lock.c:38)

第22和37行分别显示子线程和主线程在中断之前,都锁在哪行,这样就更容易定位问题了。

死锁问题分析的利器——valgrind的DRD和Helgrind相关推荐

  1. 互斥量、读写锁长占时分析的利器——valgrind的DRD

    在进行多线程编程时,我们可能会存在同时操作(读.写)同一份内存的可能性.为了保证数据的正确性,我们往往会使用互斥量.读写锁等同步方法.(转载请指明出于breaksoftware的csdn博客) 互斥量 ...

  2. 动态执行流程分析和性能瓶颈分析的利器——valgrind的callgrind

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用callgrind工具进行动态执行流程分析和性能瓶颈分析.(转载请指明出于brea ...

  3. 内存问题分析的利器——valgrind的memcheck

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用memcheck工具分析各种内存问题.(转载请指明出于breaksoftware的 ...

  4. 数据竞争(data race)问题分析的利器——valgrind的Helgrind

    数据竞争(data race)是指在非线程安全的情况下,多线程对同一个地址空间进行写操作.一般来说,我们都会通过线程同步方法来保证数据的安全,比如采用互斥量或者读写锁.但是由于某些笔误或者设计的缺陷, ...

  5. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

  6. 堆状态分析的利器——valgrind的DHAT

    在<堆问题分析的利器--valgrind的massif>一文中,我们介绍了如何使用massif查看和分析堆分配/释放的问题.但是除了申请和释放,堆空间还有其他问题,比如堆空间的使用率.使用 ...

  7. mysql 1061原因_MySQL死锁问题分析及解决方法实例详解(转)

    出处:http://www.jb51.net/article/51508.htm MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下: 1.MySQL常用存储 ...

  8. Innodb锁系统 Insert/Delete 锁处理及死锁示例分析

    A.INSERT 插入操作在函数btr_cur_optimistic_insert->btr_cur_ins_lock_and_undo->lock_rec_insert_check_an ...

  9. mysql并发插入死锁_MySQL: 并发replace into的死锁问题分析-阿里云开发者社区

    测试版本:MySQL5.6.23测试表: create table t1 (a int auto_increment primary key, b int, c int, unique key (b) ...

最新文章

  1. 从C语言的角度重构数据结构系列(一)-数据结构入门之逻辑结构与物理结构
  2. 【论文解读】打破常规,逆残差模块超强改进,新一代移动端模型MobileNeXt来了!精度速度双超MobileNetV2...
  3. oracle别名用双引号,Oracle别名大小写 -----解决方案
  4. 真是个狠人!开学第一天,这批小学生的造型刷爆朋友圈!
  5. P7920-[Kubic]Permutation
  6. 进程与线程的区别(面试题)
  7. Python(1)-源起、设计目标、设计哲学、特点
  8. python智能机器人设计与实现_从AI模型到智能机器人:基于Python与TensorFlow
  9. arcgis 服务网页打开需要输入用户名和密码问题解决
  10. 网游UI解决方案的选择(作者 鸣·铭)
  11. Flutter初步-第一个电视直播APP
  12. 《IPD:华为研发之道》读书介绍
  13. 有道 - 扇贝 - 海词词典发音链接
  14. win7安装系统后关闭计算机,完美重装系统win7后电脑为什么总是自动关机?
  15. AW笔记本升级SSD,外接双屏中的一些注意事项
  16. 我和欧阳娜娜一起搞研发
  17. 搜狗输入法怎么打印间隔号
  18. Linear Algebra 线性代数
  19. ROOK-01 集群简单搭建和卸载
  20. [凸多边形最大内切圆][半平面交]Most Distant Point from the Sea POJ3525

热门文章

  1. javascript的Array对象
  2. 使用Java对轨迹进行抽稀,并生成mvt(Map Vector Tile)瓦片
  3. opencvmediapipe 人脸检测+摄像头实时
  4. Paper8:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
  5. POJ - 3417 Network LCA+树上差分
  6. 【python】一次移动平均算法
  7. TANDEM 基于深度多视图立体视觉的实时跟踪和稠密建图
  8. elementUI 写一个表头列名、表体单元格样式、翻页器相对较为动态的表格el-table
  9. Python入门基础教程 Working with Python – Introductory Level
  10. cannot find main module 解决办法