一、 概述
C++多线程开发中,容易出现死锁导致程序挂起的现象。
关于死锁的信息,见百度百科http://baike.baidu.com/view/121723.htm

解决步骤分为三步:
1、检测死锁线程。
2、打印线程信息。
3、修改死锁程序。

二、 程序示例
VS2005创建支持MFC的win32控制台程序。
代码见示例代码DeadLockTest.cpp。

  1. // DeadLockTest.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include "DeadLockTest.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #endif
  8. // The one and only application object
  9. CWinApp theApp;
  10. using namespace std;
  11. CRITICAL_SECTION cs1;
  12. CRITICAL_SECTION cs2;
  13. CRITICAL_SECTION csprint;
  14. //初始化关键代码段
  15. void InitMyCriticalSection();
  16. //删除关键代码段
  17. void DeleteMyCriticalSection();
  18. //打印信息
  19. void PrintString(const CString& strInfo);
  20. DWORD WINAPI Thread1(LPVOID lpParameter);
  21. DWORD WINAPI Thread2(LPVOID lpParameter);
  22. int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
  23. {
  24. int nRetCode = 0;
  25. // initialize MFC and print and error on failure
  26. if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  27. {
  28. // TODO: change error code to suit your needs
  29. _tprintf(_T("Fatal Error: MFC initialization failed\n"));
  30. nRetCode = 1;
  31. return nRetCode;
  32. }
  33. //初始化关键代码段
  34. InitMyCriticalSection();
  35. //创建线程
  36. HANDLE hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
  37. HANDLE hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
  38. //等待线程结束
  39. WaitForSingleObject(hThread1, INFINITE);
  40. WaitForSingleObject(hThread2, INFINITE);
  41. //关闭线程句柄
  42. CloseHandle(hThread1);
  43. CloseHandle(hThread2);
  44. //释放关键代码段
  45. DeleteMyCriticalSection();
  46. return nRetCode;
  47. }
  48. void InitMyCriticalSection()
  49. {
  50. InitializeCriticalSection(&cs1);
  51. InitializeCriticalSection(&cs2);
  52. InitializeCriticalSection(&csprint);
  53. }
  54. void DeleteMyCriticalSection()
  55. {
  56. DeleteCriticalSection(&cs1);
  57. DeleteCriticalSection(&cs2);
  58. DeleteCriticalSection(&csprint);
  59. }
  60. DWORD WINAPI Thread1(LPVOID lpParameter)
  61. {
  62. for (int i = 0; i < 5; i++)
  63. {
  64. EnterCriticalSection(&cs1);
  65. Sleep(500);
  66. EnterCriticalSection(&cs2);
  67. PrintString(_T("Thread1"));
  68. LeaveCriticalSection(&cs2);
  69. LeaveCriticalSection(&cs1);
  70. }
  71. return 1;
  72. }
  73. DWORD WINAPI Thread2(LPVOID lpParameter)
  74. {
  75. for (int i = 0; i < 5; i++)
  76. {
  77. EnterCriticalSection(&cs2);
  78. Sleep(500);
  79. EnterCriticalSection(&cs1);
  80. PrintString(_T("Thread2"));
  81. LeaveCriticalSection(&cs1);
  82. LeaveCriticalSection(&cs2);
  83. }
  84. return 1;
  85. }
  86. void PrintString(const CString& strInfo)
  87. {
  88. EnterCriticalSection(&csprint);
  89. wcout<<(const TCHAR*)strInfo<<endl;
  90. LeaveCriticalSection(&csprint);
  91. }

运行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以及关键代码段进入信息。

  1. DWORD WINAPI Thread1(LPVOID lpParameter)
  2. {
  3. CString strThreadID = _T("");
  4. strThreadID.Format(_T("%d"), GetCurrentThreadId());
  5. CString strPrintInfo = _T("");
  6. for (int i = 0; i < 5; i++)
  7. {
  8. EnterCriticalSection(&cs1);
  9. strPrintInfo = _T("");
  10. strPrintInfo += _T("Thread1 ");
  11. strPrintInfo += strThreadID;
  12. strPrintInfo += _T(" EnterCriticalSection(&cs1)");
  13. PrintString(strPrintInfo);
  14. Sleep(500);
  15. EnterCriticalSection(&cs2);
  16. strPrintInfo = _T("");
  17. strPrintInfo += _T("Thread1 ");
  18. strPrintInfo += strThreadID;
  19. strPrintInfo += _T(" EnterCriticalSection(&cs2)");
  20. PrintString(strPrintInfo);
  21. LeaveCriticalSection(&cs2);
  22. LeaveCriticalSection(&cs1);
  23. }
  24. return 1;
  25. }
  26. DWORD WINAPI Thread2(LPVOID lpParameter)
  27. {
  28. CString strThreadID = _T("");
  29. strThreadID.Format(_T("%d"), GetCurrentThreadId());
  30. CString strPrintInfo = _T("");
  31. for (int i = 0; i < 5; i++)
  32. {
  33. EnterCriticalSection(&cs2);
  34. strPrintInfo = _T("");
  35. strPrintInfo += _T("Thread2 ");
  36. strPrintInfo += strThreadID;
  37. strPrintInfo += _T(" EnterCriticalSection(&cs2)");
  38. PrintString(strPrintInfo);
  39. Sleep(500);
  40. EnterCriticalSection(&cs1);
  41. strPrintInfo = _T("");
  42. strPrintInfo += _T("Thread2 ");
  43. strPrintInfo += strThreadID;
  44. strPrintInfo += _T(" EnterCriticalSection(&cs1)");
  45. PrintString(strPrintInfo);
  46. LeaveCriticalSection(&cs1);
  47. LeaveCriticalSection(&cs2);
  48. }
  49. return 1;
  50. }

运行结果如下。

五、 死锁修改
线程互斥进行修改,Thread1与Thread2对关键代码段的进入与退出顺序改为相同。程序运行正常。
修改后线程代码。

  1. DWORD WINAPI Thread1(LPVOID lpParameter)
  2. {
  3. for (int i = 0; i < 5; i++)
  4. {
  5. EnterCriticalSection(&cs1);
  6. Sleep(500);
  7. EnterCriticalSection(&cs2);
  8. PrintString(_T("Thread1"));
  9. LeaveCriticalSection(&cs2);
  10. LeaveCriticalSection(&cs1);
  11. }
  12. return 1;
  13. }
  14. DWORD WINAPI Thread2(LPVOID lpParameter)
  15. {
  16. for (int i = 0; i < 5; i++)
  17. {
  18. EnterCriticalSection(&cs1);
  19. Sleep(500);
  20. EnterCriticalSection(&cs2);
  21. PrintString(_T("Thread2"));
  22. LeaveCriticalSection(&cs2);
  23. LeaveCriticalSection(&cs1);
  24. }
  25. return 1;
  26. }

C++死锁解决心得的更多相关文章

  1. SqlServer定时备份数据库和定时杀死数据库死锁解决

    上周五组长对我说了一句要杀死数据库的死锁进程,有时候同一时刻不停写入数据库会造成这种情况的发生,因为自己对数据库不是很熟悉,突然组长说了我也就决定一定要倒腾一下,不然自己怎么提高呢?现在不研究,说不定 ...

  2. Oracle 表死锁 解决

    问题:更新的Update语句一直在更新 卡在执行update语句的地方. 清除的方法: Oracle表死锁解除   我是在plsql中处理  1.先查询  select * from v$locked ...

  3. sqlserver2008 死锁解决方法及性能优化方法

    sqlserver2008 死锁解决方法及性能优化方法 原文: http://blog.csdn.net/kuui_chiu/article/details/48621939 十步优化SQL Serv ...

  4. jvm死锁解决

    那我们怎么确定一定是死锁呢?有两种方法. 1>使用JDK给我们的的工具JConsole,可以通过打开cmd然后输入jconsole打开. 1)连接到需要查看的进程.

  5. mysql死锁+解决

    自己作死,navicat不恰当的操作导致了表死锁,操作如下: 给表新加字段:name 没有选择允许为空,但是有没有设置初始值,所以运行的结果就是数据库表里有了name不允许为空但是确实为空的记录: 然 ...

  6. SQL Server 表,记录 死锁解决办法

    我自己的数据库表记录死锁后的 根据以下资料的 解决方案: 1. 先根据以下语句 查询 哪些表被 死锁,及 死锁的  spid SELECT request_session_id spid,OBJECT ...

  7. PL/SQL 出现死锁解决办法

    转自:https://blog.csdn.net/u013015629/article/details/48005763 在PL/SQL中操作数据表时,长时间没反应,并且编辑某个表中数据时,出现“re ...

  8. ADO访问Access数据库错误解决心得随笔

    最近在用ADO访问Access数据库的时候出现了一个奇怪的错误,觉得有必要记录下来,和大家分享一下. 环境 win7 x86系统: VS2012编译器: Office2010: Access2000~ ...

  9. DB2死锁解决办法

    db2 命令行,1.用管理员用户登录:db2 connect to 你的数据库名 user 用户名 using 密码 2.db2 "get snapshot for locks on 数据库 ...

随机推荐

  1. 老司机带你用vagrant打造一站式python开发测试环境

      前言 作为一个学习和使用Python的老司机,好像应该经常总结一点东西的,让新司机尽快上路,少走弯路,然后大家一起愉快的玩耍. 今天,咱们就使用vagrant配合xshell打造一站式Python ...

  2. 2-4. BCD解密(10)

    BCD数是用一个字节来表达两位十进制的数,每四个比特表示一位.所以如果一个BCD数的十六进制是0x12,它表达的就是十进制的12.但是小明没学过BCD,把所有的BCD数都当作二进制数转换成十进制输出了 ...

  3. *循环-01. 求整数段和【help】

    /* * Main.c * 循环-01. 求整数段和 * Created on: 2014年6月18日 * Author: Boomkeeper ***测试木有通过**** */ #include & ...

  4. NetworkManager配置网络——Red Hat 7 && CGSL V5

      NetworkManager服务管理网络方便在哪? 很重要的一点是:一个设备可以对应多个配置文件,但是同一时间只能有一个配置文件生效,这对于频率切换网络环境是非常方便的,不用再跑那个目录下去改配置 ...

  5. API 设计: RAML、Swagger、Blueprint三者的比较

    API设计工具中常常会拿RAML.Swagger.Blueprint这三种工具进行讨论比较,它们都是用来描述和辅助API开发的,只是它们之间的侧重有所不同. RAML RAML(RESTful API ...

  6. C语言的本质(6)——位运算

    位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进制位的问题.C语言提供了6个位操作运算符.这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型 ...

  7. Codeforces 734F Anton and School(位运算)

    [题目链接] http://codeforces.com/problemset/problem/734/F [题目大意] 给出数列b和数列c,求数列a,如果不存在则输出-1 [题解] 我们发现: bi ...

  8. POJ 1182 食物链(并查集拆点)

    [题目链接] http://poj.org/problem?id=1182 [题目大意] 草原上有三种物种,分别为A,B,C A吃B,B吃C,C吃A. 1 x y表示x和y是同类,2 x y表示x吃y ...

  9. Linux 下防火墙端口设置

    方式1:     /sbin/iptables -I INPUT -p tcp --dport 8011 -j ACCEPT  #开启8011端口      /etc/rc.d/init.d/ipta ...

  10. Genealogical tree(拓扑结构+邻接表+优先队列)

    Genealogical tree Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) ...