C++死锁解决心得
一、 概述
C++多线程开发中,容易出现死锁导致程序挂起的现象。
关于死锁的信息,见百度百科http://baike.baidu.com/view/121723.htm。
解决步骤分为三步:
1、检测死锁线程。
2、打印线程信息。
3、修改死锁程序。
二、 程序示例
VS2005创建支持MFC的win32控制台程序。
代码见示例代码DeadLockTest.cpp。
- // DeadLockTest.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include "DeadLockTest.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif
- // The one and only application object
- CWinApp theApp;
- using namespace std;
- CRITICAL_SECTION cs1;
- CRITICAL_SECTION cs2;
- CRITICAL_SECTION csprint;
- //初始化关键代码段
- void InitMyCriticalSection();
- //删除关键代码段
- void DeleteMyCriticalSection();
- //打印信息
- void PrintString(const CString& strInfo);
- DWORD WINAPI Thread1(LPVOID lpParameter);
- DWORD WINAPI Thread2(LPVOID lpParameter);
- int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
- {
- int nRetCode = 0;
- // initialize MFC and print and error on failure
- if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
- {
- // TODO: change error code to suit your needs
- _tprintf(_T("Fatal Error: MFC initialization failed\n"));
- nRetCode = 1;
- return nRetCode;
- }
- //初始化关键代码段
- InitMyCriticalSection();
- //创建线程
- HANDLE hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- HANDLE hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- //等待线程结束
- WaitForSingleObject(hThread1, INFINITE);
- WaitForSingleObject(hThread2, INFINITE);
- //关闭线程句柄
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- //释放关键代码段
- DeleteMyCriticalSection();
- return nRetCode;
- }
- void InitMyCriticalSection()
- {
- InitializeCriticalSection(&cs1);
- InitializeCriticalSection(&cs2);
- InitializeCriticalSection(&csprint);
- }
- void DeleteMyCriticalSection()
- {
- DeleteCriticalSection(&cs1);
- DeleteCriticalSection(&cs2);
- DeleteCriticalSection(&csprint);
- }
- DWORD WINAPI Thread1(LPVOID lpParameter)
- {
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs1);
- Sleep(500);
- EnterCriticalSection(&cs2);
- PrintString(_T("Thread1"));
- LeaveCriticalSection(&cs2);
- LeaveCriticalSection(&cs1);
- }
- return 1;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)
- {
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs2);
- Sleep(500);
- EnterCriticalSection(&cs1);
- PrintString(_T("Thread2"));
- LeaveCriticalSection(&cs1);
- LeaveCriticalSection(&cs2);
- }
- return 1;
- }
- void PrintString(const CString& strInfo)
- {
- EnterCriticalSection(&csprint);
- wcout<<(const TCHAR*)strInfo<<endl;
- LeaveCriticalSection(&csprint);
- }
运行DeadLockTest.exe,程序挂起。
三、 死锁检测
检测工具见《Windows核心编程》,第9章9.8.6节LockCop检测工具。
工具源码地址:http://www1.wintellect.com/Resources/Details/86。
LockCop可使用vs2010编译成功。
备注:该工具使用了Windows Vista/ 7提供的WCT API,故需要在Windows Vista/ 7系统运行LockCop检测工具。
检测,挂起的DeadLockTest.exe,得到线程信息。
检测到程序挂起由死锁引起。
线程4014:等待线程772、线程4012完成。
线程772:拥有关键代码段A,等待关键代码段B(被线程4012拥有)。
线程4012:拥有关键代码段B,等待关键代码段A(被线程772拥有)。
线程772与4012互相等待,程序发生死锁现象。
四、 打印信息
为了便于查找问题,我们加上线程打印信息。
打印线程名称、线程ID以及关键代码段进入信息。
- DWORD WINAPI Thread1(LPVOID lpParameter)
- {
- CString strThreadID = _T("");
- strThreadID.Format(_T("%d"), GetCurrentThreadId());
- CString strPrintInfo = _T("");
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs1);
- strPrintInfo = _T("");
- strPrintInfo += _T("Thread1 ");
- strPrintInfo += strThreadID;
- strPrintInfo += _T(" EnterCriticalSection(&cs1)");
- PrintString(strPrintInfo);
- Sleep(500);
- EnterCriticalSection(&cs2);
- strPrintInfo = _T("");
- strPrintInfo += _T("Thread1 ");
- strPrintInfo += strThreadID;
- strPrintInfo += _T(" EnterCriticalSection(&cs2)");
- PrintString(strPrintInfo);
- LeaveCriticalSection(&cs2);
- LeaveCriticalSection(&cs1);
- }
- return 1;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)
- {
- CString strThreadID = _T("");
- strThreadID.Format(_T("%d"), GetCurrentThreadId());
- CString strPrintInfo = _T("");
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs2);
- strPrintInfo = _T("");
- strPrintInfo += _T("Thread2 ");
- strPrintInfo += strThreadID;
- strPrintInfo += _T(" EnterCriticalSection(&cs2)");
- PrintString(strPrintInfo);
- Sleep(500);
- EnterCriticalSection(&cs1);
- strPrintInfo = _T("");
- strPrintInfo += _T("Thread2 ");
- strPrintInfo += strThreadID;
- strPrintInfo += _T(" EnterCriticalSection(&cs1)");
- PrintString(strPrintInfo);
- LeaveCriticalSection(&cs1);
- LeaveCriticalSection(&cs2);
- }
- return 1;
- }
运行结果如下。
五、 死锁修改
线程互斥进行修改,Thread1与Thread2对关键代码段的进入与退出顺序改为相同。程序运行正常。
修改后线程代码。
- DWORD WINAPI Thread1(LPVOID lpParameter)
- {
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs1);
- Sleep(500);
- EnterCriticalSection(&cs2);
- PrintString(_T("Thread1"));
- LeaveCriticalSection(&cs2);
- LeaveCriticalSection(&cs1);
- }
- return 1;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)
- {
- for (int i = 0; i < 5; i++)
- {
- EnterCriticalSection(&cs1);
- Sleep(500);
- EnterCriticalSection(&cs2);
- PrintString(_T("Thread2"));
- LeaveCriticalSection(&cs2);
- LeaveCriticalSection(&cs1);
- }
- return 1;
- }
C++死锁解决心得的更多相关文章
- SqlServer定时备份数据库和定时杀死数据库死锁解决
上周五组长对我说了一句要杀死数据库的死锁进程,有时候同一时刻不停写入数据库会造成这种情况的发生,因为自己对数据库不是很熟悉,突然组长说了我也就决定一定要倒腾一下,不然自己怎么提高呢?现在不研究,说不定 ...
- Oracle 表死锁 解决
问题:更新的Update语句一直在更新 卡在执行update语句的地方. 清除的方法: Oracle表死锁解除 我是在plsql中处理 1.先查询 select * from v$locked ...
- sqlserver2008 死锁解决方法及性能优化方法
sqlserver2008 死锁解决方法及性能优化方法 原文: http://blog.csdn.net/kuui_chiu/article/details/48621939 十步优化SQL Serv ...
- jvm死锁解决
那我们怎么确定一定是死锁呢?有两种方法. 1>使用JDK给我们的的工具JConsole,可以通过打开cmd然后输入jconsole打开. 1)连接到需要查看的进程.
- mysql死锁+解决
自己作死,navicat不恰当的操作导致了表死锁,操作如下: 给表新加字段:name 没有选择允许为空,但是有没有设置初始值,所以运行的结果就是数据库表里有了name不允许为空但是确实为空的记录: 然 ...
- SQL Server 表,记录 死锁解决办法
我自己的数据库表记录死锁后的 根据以下资料的 解决方案: 1. 先根据以下语句 查询 哪些表被 死锁,及 死锁的 spid SELECT request_session_id spid,OBJECT ...
- PL/SQL 出现死锁解决办法
转自:https://blog.csdn.net/u013015629/article/details/48005763 在PL/SQL中操作数据表时,长时间没反应,并且编辑某个表中数据时,出现“re ...
- ADO访问Access数据库错误解决心得随笔
最近在用ADO访问Access数据库的时候出现了一个奇怪的错误,觉得有必要记录下来,和大家分享一下. 环境 win7 x86系统: VS2012编译器: Office2010: Access2000~ ...
- DB2死锁解决办法
db2 命令行,1.用管理员用户登录:db2 connect to 你的数据库名 user 用户名 using 密码 2.db2 "get snapshot for locks on 数据库 ...
随机推荐
- UIALertView与UIAlertViewDelegate的基本用法
首先,视图控制器必须得实现协议UIAlertViewDelegate中的方法,并指定delegate为self,才能使弹出的Alert窗口响应点击事件. 具体代码如下: ViewController. ...
- JavaScript基本概念(操作符)
一元操作符 一元操作符在处理所有的非数值时,相当于将该值经过Number()转换成数值,如 +"12" 将把 "12" 字符串转换为数字. 位操作符 负数在计算 ...
- [转]C 语言指针的使用
第一章 指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址. 要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的 类型,指针的值或者叫指针所指向的内存区,还有 ...
- Java开发工具IntelliJ IDEA单元测试和代码覆盖率图解
原文 http://www.cnblogs.com/xiongmaopanda/p/3314660.html Java开发工具IntelliJ IDEA使用教程:单元测试和代码覆盖率 本文将展示如何使 ...
- 量身定制顺美男女西服、衬衫、大衣、T恤等 - 北京58同城
量身定制顺美男女西服.衬衫.大衣.T恤等 - 北京58同城 量身定制顺美男女西服.衬衫.大衣.T恤等 发布时间:2014-04-11浏览2次
- 一个C/C++结构体初始化有趣的现象
我们知道C语言当中结构可以使用{}进行初始化,例如有结构体定义如下: typedef struct type_t { int a; int b; int c; int d; }type_t; 我们可以 ...
- table+js实现网站左侧列表下拉隐藏
<script language="javascript"> function showHide(obj){ ...
- data按钮
1.加载状态 通过按钮(Button)插件,您可以添加进一些交互,比如控制按钮状态,或者为其他组件(如工具栏)创建按钮组. 如需向按钮添加加载状态,只需要简单地向 button 元素添加 data-l ...
- Struts 2.x Unable to load configuration. - action
问题分析:遇到该问题一般是struts中某个配置文件没有正确配置,比如: 1.class中的TestAction没有成功加载: <constant name="struts.i18n. ...
- [Android]Plug-in com.android.ide.eclipse.adt was unable to load class com.android.ide
今天启动eclipse的时候报了上述错误,打开xml是都报错.其实解决方法很简单:重启eclipse即可.