Windbg调试互斥体(Mutex)死锁
一. 测试代码
#include <windows.h>
#include <tchar.h>
#include <process.h>
HANDLE hMutexA = NULL;
HANDLE hMutexB = NULL;
unsigned __stdcall ThreadProc1(void * pArg) {
WaitForSingleObject(hMutexA, INFINITE);
Sleep(500);
WaitForSingleObject(hMutexB, INFINITE);
printf("+++\n");
ReleaseMutex(hMutexB);
ReleaseMutex(hMutexA);
return 0;
}
unsigned __stdcall ThreadProc2(void * pArg) {
WaitForSingleObject(hMutexB, INFINITE);
Sleep(500);
WaitForSingleObject(hMutexA, INFINITE);
printf("...\n");
ReleaseMutex(hMutexA);
ReleaseMutex(hMutexB);
return 0;
}
int main()
{
hMutexA = CreateMutex(NULL, FALSE, TEXT("MutexA"));
hMutexB = CreateMutex(NULL, FALSE, TEXT("MutexB"));
// 启动线程
HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadProc2, NULL, 0, NULL);
getchar();
// 等待线程退出并关闭句柄
if (hThread1) {
WaitForSingleObject(hThread1, INFINITE);
CloseHandle(hThread1);
}
if (hThread2) {
WaitForSingleObject(hThread2, INFINITE);
CloseHandle(hThread2);
}
// 关闭句柄
if(hMutexA)
CloseHandle(hMutexA);
if(hMutexB)
CloseHandle(hMutexB);
return 0;
}
二. 死锁原理
程序生成了2个线程(线程1、线程2)和2个互斥体MutexA和MutexB。
观察线程执行代码可知,这是一个典型的死锁用例,2个线程相互等待。
线程1: 拥有MutexA --> 过一段时间(sleep) ---> 想拥有MutexB
线程2: 拥有MutexB --> 过一段时间(sleep) ---> 想拥有MutexA
线程1想拥有属于线程2的MutexB,而线程2却想拥有属于线程1的MutexA,互不松手,就只能都等着了。
三. 上调试器
~*kvn
查看所有线程调用堆栈:
从线程#1栈帧03可以看到其正在等待句柄00000038。
从线程#2栈帧03可以看到其正在等待句柄00000034。
即:
线程#1(ID:22f4)--->等待句柄38
线程#2(ID:33bc)---> 等待句柄34
到底句柄00000034和00000038是什么类型的,可以使用!handle
命令查看:
从图中可以看到:
句柄00000034为名为MutexA的互斥体,被线程ID:2264 拥有。
句柄00000038为名为MutexB的互斥体,被线程ID:33bc 拥有。
即:
线程#1(ID:22f4)等待00000038(互斥体MutexA ),拥有00000034(互斥体MutexB)
线程#2(ID:33bc)等待句柄00000034(互斥体MutexB ),拥有00000038(互斥体MutexA)
所以,爱就是放手,有时候放手会让彼此过得更好。
Windbg调试互斥体(Mutex)死锁的更多相关文章
- Linux系统中的信号量(semphore)与互斥体(mutex)
http://www.embexperts.com/viewthread.php?tid=31 两者最大区别:信号量可以允许多个线程进入临界区,而互斥体只允许一个线程进入临界区.本贴将描述信号量与互斥 ...
- C#互斥体——Mutex
Mutex对象是一个同步基元,可以用来做线程间的同步. 若多个线程需要共享一个资源,可以在这些线程中使用Mutex同步基元.当某一个线程占用Mutex对象时,其他也需要占用Mutex的线程将处于挂起状 ...
- [原]调试实战——使用windbg调试TerminateThread导致的死锁
原调试debugwindbg死锁deadlock 前言 项目里的一个升级程序偶尔会死锁,查看dump后发现是死在了ShellExecuteExW里.经验少,不知道为什么,于是在高端调试论坛里发帖求助, ...
- [原]调试实战——使用windbg调试excel启动时死锁
原调试debugwindbg死锁deadlock 前言 这是几年前在项目中遇到的一个死锁问题,在博客园发布过.我对之前的笔记进行了整理重新发布于此. 本文假设小伙伴们知道一些基本概念,比如什么是.du ...
- Windbg调试关键区(CriticalSection)死锁
一. 准备工作 这里一个有关键区锁死问题的程序,运行之后依次点击"CS锁死"按钮.右上角退出按钮,程序就会卡死.(图1) 对于眼下的这个问题,界面完全失去响应,这说明负责消息处理的 ...
- windows系统调用 互斥体mutex
#include "iostream" #include "windows.h" using namespace std; class CCountUpDown ...
- 41、Thead线程 System.Thread与互斥体Mutex
Thead线程 System.Thread 使用Thread类可以创建和控制线程.下面的代码是创建和启动一个新线程的简单例子.Thread 类的构造函数重载为接受ThreadStart和Paramet ...
- 互斥体与互锁 <第五篇>
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)).互斥体禁止多个线程同时进入受保护的代码“临界区”.因此,在任意时刻,只有一个线程被允许进入这 ...
- 转载 互斥体与互锁 <第五篇>
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex)).互斥体禁止多个线程同时进入受保护的代码“临界区”.因此,在任意时刻,只有一个线程被允许进入这 ...
随机推荐
- mysql主从数据库设置备忘
[mysqld] binlog-do-db = databasename1 binlog-do-db = databasename2 binlog-do-db = databasename3 -- 且 ...
- 开始编写寄几的 CSS 基础库
前言 在现在的互联网业务中,前端开发人员往往需要支持比较多的项目数量.很多公司只有 1-2 名前端开发人员,这其中还不乏规模比较大的公司.这时前端同学就需要独挡一面支持整个公司上下的前端业务,项目如流 ...
- Scikit-Learn与决策树
Scikit-Learn(决策树)可以用于方法分类和回归. 一.分类 sklearn.tree.DecisionTreeClassifier(criterion='gini', splitter='b ...
- 【SignalR学习系列】2. 第一个SignalR程序
新建项目 1.使用VisualStudio 2015 新建一个Web项目 2.选择空模板 3.添加一个新的SignalR Hub Class (v2)类文件,并修改类名为ChatHub 4.修改Cha ...
- 华为软件开发云对比Jenkins-JavaWeb项目持续部署方式
一.前言:Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成和持续部署变成可能. 本文 ...
- year:2017 month:7 day:20
2017-07-20 JavaScript(Dom) 1:获取节点对象 document.getElementById("html元素的id") document.getEleme ...
- python关于list的三个内置函数filter(), map(), reduce()
''' Python --version :Python 2.7.11 Quote : https://docs.python.org/2/tutorial/datastructures.html#m ...
- 超强、超详细Redis数据库入门教程(转载)
这篇文章主要介绍了超强.超详细Redis入门教程,本文详细介绍了Redis数据库各个方面的知识,需要的朋友可以参考下 [本教程目录] 1.redis是什么 2.redis的作者何许人也 3.谁在使 ...
- Docker跨主机网络——overlay
前言 在Docker网络--单host网络一文中,我为大家总结了Docker的单机网络相关知识和操作,单机网络比较容易.本文我为大家总结Docker跨主机通信相关知识.同样本文大部分内容以CloudM ...
- JDBC连接数据库的基本步骤
第一步:注册驱动==>:Class.forName("数据库驱动的完整名称(mysql的数据库驱动名称:com.mysql.jbdc.Driver)"); 第二步:创建一个数 ...