zoukankan      html  css  js  c++  java
  • (Windbg调试四)C++死锁问题定位与分析

         C++程序异常一般有两种表现形式:程序崩溃和程序无响应。程序崩溃主要是由指针,数组越界等原因引起,这种情况可以直接通过在程序中加入Dump捕捉逻辑,分析dump文件,定位出崩溃的代码。程序无响应主要是由死循环和死锁两个原因造成的,死循环我们可以通过查看CPU使用情况来初步判断,然后转存为Dump进行分析;死锁问题是C++中最难定位和分析的一种程序异常问题,下面我们主要介绍下死锁问题的一般定位和分析方法。

    一,测试代码

         在介绍死锁分析方法之前,先看一下本文中我们使用的测试代码:

    CRITICAL_SECTION cs1;
    CRITICAL_SECTION cs2;
    
    DWORD WINAPI Thread1(LPVOID lpParameter);
    DWORD WINAPI Thread2(LPVOID lpParameter);
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
    {
    	//初始化关键代码段
    	InitializeCriticalSection(&cs1);
    	InitializeCriticalSection(&cs2);
    
    	//创建线程
    	HANDLE hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
    	HANDLE hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
    
    	//等待线程结束
    	WaitForSingleObject(hThread1, INFINITE);
    	WaitForSingleObject(hThread2, INFINITE);
    	Sleep(2000);
    
    	//关闭线程句柄
    	CloseHandle(hThread1);
    	CloseHandle(hThread2);
    
    	//释放关键代码段
    	DeleteCriticalSection(&cs1);
    	DeleteCriticalSection(&cs2);
    
    	return 0;
    }
    
    DWORD WINAPI Thread1(LPVOID lpParameter)
    {
    	for (int i = 0; i < 10; i++)
    	{
    		EnterCriticalSection(&cs1);
    		Sleep(500);
    		EnterCriticalSection(&cs2);
    
    		std::cout << "Thread1" << std::endl;
    
    		LeaveCriticalSection(&cs2);
    		LeaveCriticalSection(&cs1);
    	}
    	return 1;
    }
    
    DWORD WINAPI Thread2(LPVOID lpParameter)
    {
    	for (int i = 0; i < 10; i++)
    	{
    		EnterCriticalSection(&cs2);
    		Sleep(500);
    		EnterCriticalSection(&cs1);
    
    		std::cout << "Thread2" << std::endl;
    
    		LeaveCriticalSection(&cs1);
    		LeaveCriticalSection(&cs2);
    	}
    	return 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    在这个例子中,Thread1等待Thread2,Thread2等待Thread1,同时主线程等待着Thread1和Thread2,三个线程陷入死锁状态。

    二,等待链

    在这里插入图片描述
         等待链是线程和同步对象的交替序列;每个线程都在等待它后面的对象,该对象由链中的后续线程拥有。通过分析等待链,我们可以清晰地看到各个子线程/子进程挂起所在等待的下一个线程/进程。(等待链更多知识请转至Wait Chain Traversal
         在《Windows核心编程》一书附带的源码09-LockCop中,详细介绍了WCT的编码实现,感兴趣的可以去阅读一下源码,附上下载链接(Windows核心编程(第5版中文版) 源码)。编译09-LockCop,我们可以得到09-LockCop.exe应用程序,打开改程序,选择我们的进程DeadLockTest.exe,分析如下:
    在这里插入图片描述
         线程8248等待线程9524,9524在等待6432,而6432又在等待9524,陷入了互相等待的处境中,导致死锁。因此可以确认DeadLockTest.exe的无响应是由死锁造成的。
         我们也可以直接通过windows的任务管理器来检测一个程序是否陷入死锁,打开任务管理器-性能-资源监视器,选中我们的测试程序,右键菜单“分析等待链”:
    在这里插入图片描述
         分析结果如下:
    在这里插入图片描述
         可以看到9524线程与6432线程陷入了互相等待锁资源的处境,程序死锁。

    三,死锁的定位和分析

         如果死锁的程序刚好在我们自己的开发机器上,那么使用WinDbg的Attach To A Proccess功能将死锁程序直接附加到WinDbg中进行分析;如果不在我们的机器上,可以通过Windows的资源管理器对进行进行创建转储文件转换为dump(注意32位和64位的区别),再通过WinDbg对dump进行分析。为了方便,我们直接以Attach方式讲解。
         Attach程序后,输入!locks命令查看锁的状态:
    在这里插入图片描述
         总共有两个锁cs1(012e4394)和cs2(012e437c),这两个锁的LockCount(表示还有多少个线程在等待这个临界区)都为1,说明这两个锁都处于等待状态。
         再输入~*kb查看一下当前各个线程的堆栈:
    在这里插入图片描述
         线程2534和线程1920都处于等待状态,线程2534等待锁012e437c,线程1920等待锁012e4394。再结合上面的锁信息可以知道,锁012e4394被线程2534拥有,锁012e437c被线程1920拥有,所以这两个线程陷入了互相等待的死锁中。等待锁的源码也直接定位到了,问题解决。

    本文举例比较简单,主要是介绍死锁问题的定位以及分析的一般方法,具体问题还要视情况具体分析。

    from:https://blog.csdn.net/bajianxiaofendui/article/details/86983550

  • 相关阅读:
    Python (一)Tkinter窗口组件:Label
    Python (八)Tkinter窗口组件:Scrollbar
    Python (四)Tkinter窗口组件:Radiobutton
    Python (五)Tkinter窗口组件:LabelFrame
    Python (三)Tkinter窗口组件:Checkbutton
    Scrapy安装及相关知识点概括
    Python (九)Tkinter窗口组件:Scale
    Python (六)Tkinter窗口组件:Entry
    电脑通过蓝牙适配器连接手机与蓝牙耳机之经验
    Noi2018 归途
  • 原文地址:https://www.cnblogs.com/lidabo/p/14381383.html
Copyright © 2011-2022 走看看