windbg经典死锁分析实例

死锁经典代码(代码来源:http://www.debuginfo.com/examples/src/DeadLockDemo.cpp):

#include <windows.h>
#include <tchar.h>
#include <process.h>
#include <stdio.h>

typedef unsigned (__stdcall *PTHREAD_START) (void*);

#define BEGINTHREADEX(lpsa, cbStack, lpStartAddr,\
	lpvThreadParm, fdwCreate, lpIDThread)          \
	((HANDLE)_beginthreadex(                     \
	(void*)(lpsa),                           \
	(unsigned)(cbStack),                     \
	(PTHREAD_START)(lpStartAddr),            \
	(void*)(lpvThreadParm),                  \
	(unsigned)(fdwCreate),                   \
	(unsigned*)(lpIDThread)))


class CCriticalSectionMy
{
public:
	CCriticalSectionMy()
	{
		InitializeCriticalSection( &m_cs );
	}
	~CCriticalSectionMy()
	{
		DeleteCriticalSection( &m_cs );
	}
	void Lock()
	{
		EnterCriticalSection( &m_cs );
	}
	void Unlock()
	{
		LeaveCriticalSection( &m_cs );
	}

private:
	CCriticalSectionMy( const CCriticalSectionMy& );
	CCriticalSectionMy& operator=( const CCriticalSectionMy& );
	CRITICAL_SECTION m_cs;
};

class CCritSecLockMy
{
public: 

	CCritSecLockMy( CCriticalSectionMy& cs ) 
		: m_rcs( cs )
	{
		_tprintf( _T("CCritSecLockMy[%u] Lock.\n"), GetCurrentThreadId() );
		m_rcs.Lock();
	}

	~CCritSecLockMy()
	{
		_tprintf( _T("~CCritSecLockMy[%u] Unlock.\n"), GetCurrentThreadId() );
		m_rcs.Unlock(); 
	}

private: 
	CCriticalSectionMy& m_rcs; 
};

DWORD WINAPI ThreadOne( LPVOID lpParam );
DWORD WINAPI ThreadTwo( LPVOID lpParam );

CCriticalSection CritSecOne;
CCriticalSection CritSecTwo;

int _tmain( int argc, TCHAR* argv[] )
{
	_tprintf( _T("Starting worker threads...\n") );
	HANDLE  hThread   = NULL;
	DWORD   ThreadId  = 0;

	hThread = BEGINTHREADEX(0, 0, ThreadOne, 0, 0, &ThreadId );
	if( hThread == NULL )
	{
		_tprintf( _T("Cannot start thread. Error: %u\n"), GetLastError() );
		return 0;
	}

	hThread = BEGINTHREADEX(0, 0, ThreadTwo, 0, 0, &ThreadId );
	if( hThread == NULL )
	{
		_tprintf( _T("Cannot start thread. Error: %u\n"), GetLastError() );
		return 0;
	}

	_tprintf( _T("Worker threads started.\n") );
	Sleep( 60 * 60 * 1000 );
	_tprintf( _T("Test complete.\n") );

	return 0;
}

DWORD WINAPI ThreadOne( LPVOID lpParam )
{
	_tprintf( _T("ThreadOne[%u] started.\n"), GetCurrentThreadId() );
	while( 1 ) 
	{
		CCritSecLockMy LockOne( CritSecOne);
		_tprintf( _T("ThreadOne[%u] acquired CritSecOne\n"), GetCurrentThreadId() );
		{
			CCritSecLockMy LockTwo( CritSecTwo);
			_tprintf( _T("ThreadOne[%u] acquired CritSecTwo.\n"), GetCurrentThreadId() );
		}
	}
	return 0;
}

DWORD WINAPI ThreadTwo( LPVOID lpParam )
{
	_tprintf( _T("ThreadTwo[%u] started.\n"), GetCurrentThreadId() );
	while( 1 ) 
	{
		CCritSecLockMy LockTwo( CritSecTwo);
		_tprintf( _T("ThreadTwo[%u] acquired CritSecTwo\n"), GetCurrentThreadId() );
		{
			CCritSecLockMy LockOne( CritSecOne);
			_tprintf( _T("ThreadTwo[%u] acquired CritSecOne\n"), GetCurrentThreadId() );
		}
	}

	return 0;
}

可以参考“获取dump的八种方式”获取dump。

分析流程:

1.设置“Symbol File Path”:srv*[MyPath]*http://msdl.microsoft.com/download/symbols;[MyPDBFilePath];

2.通过“Open Crash Dump”打开抓取的dump;

3.输入:!analyze -v分析一下:

FAULTING_IP: 
ntdll!DbgBreakPoint+0
00007ffa`704ce370 cc              int     3

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00007ffa704ce370 (ntdll!DbgBreakPoint)
   ExceptionCode: 80000003 (Break instruction exception)
  ExceptionFlags: 00000000
NumberParameters: 1
   Parameter[0]: 0000000000000000

80000003:中断指令异常;

4.输入:~*kb 观察到有线程由:ntdll!RtlpWaitOnCriticalSection

   3  Id: 74bc.5cd0 Suspend: 1 Teb: 00000000`005ba000 Unfrozen
RetAddr           : Args to Child                                                           : Call Site
00007ffa`70454c73 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`6d959b40 : ntdll!ZwWaitForAlertByThreadId+0x14
00007ffa`70454a74 : 00007ff7`a6df8150 00000000`02d2f830 00007ff7`a6df8158 00000000`6d90d3b6 : ntdll!RtlpWaitOnAddressWithTimeout+0x43
00007ffa`7044efb7 : 00000000`02d2f800 00007ff7`a6df8150 00000000`fffffffa 00000000`6d8d0a82 : ntdll!RtlpWaitOnCriticalSection+0x164
00007ffa`7044eed0 : 00000000`02d76430 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpEnterCriticalSectionContended+0xd7
00007ff7`a6df11a9 : 00007ff7`a6df68b0 00000000`00005cd0 00000000`00000002 00000000`02d2d180 : ntdll!RtlEnterCriticalSection+0x40

   4  Id: 74bc.1a2c Suspend: 1 Teb: 00000000`005bc000 Unfrozen
RetAddr           : Args to Child                                                           : Call Site
00007ffa`70454c73 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`6d959b40 : ntdll!ZwWaitForAlertByThreadId+0x14
00007ffa`70454a74 : 00007ff7`a6df8128 00000000`02e7fde0 00007ff7`a6df8130 00000000`6d90d3b6 : ntdll!RtlpWaitOnAddressWithTimeout+0x43
00007ffa`7044efb7 : 00000000`02e7fe00 00007ff7`a6df8128 00000000`fffffffa 00000000`6d8d0a82 : ntdll!RtlpWaitOnCriticalSection+0x164
00007ffa`7044eed0 : 00000000`02d76700 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpEnterCriticalSectionContended+0xd7
00007ff7`a6df12b9 : 00007ff7`a6df68b0 00000000`00001a2c 00000000`00000002 00000000`02e7d730 : ntdll!RtlEnterCriticalSection+0x40

5.输入:!locks 

CritSec Testshow!CritSecOne+0 at 00007ff7a6df8128
WaiterWoken        No
LockCount          1
RecursionCount     1
OwningThread       5cd0
EntryCount         0
ContentionCount    1
*** Locked

CritSec Testshow!CritSecTwo+0 at 00007ff7a6df8150
WaiterWoken        No
LockCount          1
RecursionCount     1
OwningThread       1a2c
EntryCount         0
ContentionCount    1
*** Locked

6.输入:!cs -l

-----------------------------------------
DebugInfo          = 0x00000000009130a0
Critical section   = 0x00007ff7a6df8128 (Testshow!CritSecOne+0x0)
LOCKED
LockCount          = 0x1
WaiterWoken        = No
OwningThread       = 0x0000000000005cd0
RecursionCount     = 0x1
LockSemaphore      = 0xFFFFFFFF
SpinCount          = 0x00000000020007d0
-----------------------------------------
DebugInfo          = 0x00000000009130e0
Critical section   = 0x00007ff7a6df8150 (Testshow!CritSecTwo+0x0)
LOCKED
LockCount          = 0x1
WaiterWoken        = No
OwningThread       = 0x0000000000001a2c
RecursionCount     = 0x1
LockSemaphore      = 0xFFFFFFFF
SpinCount          = 0x00000000020007d0

7.输入:~3kv

0:007> ~3kv
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`02d2f788 00007ffa`70454c73 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`6d959b40 : ntdll!ZwWaitForAlertByThreadId+0x14
00000000`02d2f790 00007ffa`70454a74 : 00007ff7`a6df8150 00000000`02d2f830 00007ff7`a6df8158 00000000`6d90d3b6 : ntdll!RtlpWaitOnAddressWithTimeout+0x43
00000000`02d2f7c0 00007ffa`7044efb7 : 00000000`02d2f800 00007ff7`a6df8150 00000000`fffffffa 00000000`6d8d0a82 : ntdll!RtlpWaitOnCriticalSection+0x164
00000000`02d2f870 00007ffa`7044eed0 : 00000000`02d76430 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpEnterCriticalSectionContended+0xd7
00000000`02d2f8a0 00007ff7`a6df11a9 : 00007ff7`a6df68b0 00000000`00005cd0 00000000`00000002 00000000`02d2d180 : ntdll!RtlEnterCriticalSection+0x40
0:007> ~4kv
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`02e7fd38 00007ffa`70454c73 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`6d959b40 : ntdll!ZwWaitForAlertByThreadId+0x14
00000000`02e7fd40 00007ffa`70454a74 : 00007ff7`a6df8128 00000000`02e7fde0 00007ff7`a6df8130 00000000`6d90d3b6 : ntdll!RtlpWaitOnAddressWithTimeout+0x43
00000000`02e7fd70 00007ffa`7044efb7 : 00000000`02e7fe00 00007ff7`a6df8128 00000000`fffffffa 00000000`6d8d0a82 : ntdll!RtlpWaitOnCriticalSection+0x164
00000000`02e7fe20 00007ffa`7044eed0 : 00000000`02d76700 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpEnterCriticalSectionContended+0xd7
00000000`02e7fe50 00007ff7`a6df12b9 : 00007ff7`a6df68b0 00000000`00001a2c 00000000`00000002 00000000`02e7d730 : ntdll!RtlEnterCriticalSection+0x40

8.分析:可以观察到3号线程RtlpWaitOnCriticalSection的第二个参数对象正好在4号线程的Critical Section里:

  

4号线程的RtlpWaitOnCriticalSection的第二个参数对象亦然:

边学边研究,后面补充“所以然”。

 

大神分析参考:https://blog.csdn.net/hgy413/article/details/7572097

                         https://blog.csdn.net/u010275850/article/details/73435545

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,首先你需要打开 Windbg,并连接到你想要排查的系统。然后你可以使用 !locks 命令来查看系统中所有的,并用 !dlk 命令来检查的情况。 如果你想要更深入地排查,你可以使用 !threads 命令来查看所有的线程,并使用 ~*k 命令来查看每个线程的栈。这样你就可以找到可能导致的函数调用。 此外,你还可以使用 !analyze -v 命令来分析的原因,它会对系统中的所有进行分析,并给出建议的解决方案。 最后,你可以使用 .dump /ma 命令来生成内存转储文件,然后使用 !analyze -v 命令来分析转储文件,这样你就可以在离线状态下排查。 ### 回答2: Windbg是一款用于Windows调试的强大工具,可以用于排查问题。下面将介绍如何使用Windbg来排查问题。 首先,通过命令行方式打开Windbg,然后导入相关的符号文件。接下来,可以通过以下几个步骤来查找: 1. 设置调试器为检测模式。在命令行中输入"!locks"命令,这会显示当前系统上所有的资源情况。查看输出结果,可以找到被定的对象和相应的线程信息。 2. 定位线程。使用"~*"命令列出所有的线程,然后使用"~#s"命令查看每个线程的堆栈信息。在堆栈中查找是否存在线程的迹象,例如相互等待资源或无法进一步执行的情况。 3. 分析原因。使用"!analyze"命令分析信息,这将提供一些相关的调试信息,帮助我们找到问题的根源。通常,是由于资源的竞争导致的发生。 4. 查看资源情况。通过"!handle"命令查看系统中所有的句柄信息,找到被线程所持有的句柄。然后,可以使用"!object"命令查看句柄对应的对象信息,找到造成的具体原因。 5. 解决问题。根据分析结果,采取相应的解决措施来解决问题。可能的解决办法包括:调整资源的使用顺序、增加资源的数量或使用更高级别的对象等。 通过以上步骤,我们可以利用Windbg来定位和解决问题。这个过程需要一定的调试经验和分析能力,但通过合理使用Windbg的调试命令,可以有效地排查问题,提高系统的稳定性和性能。 ### 回答3: Windbg是一种强大的调试工具,可以用来分析和解决问题。在排查时,可以按照以下步骤进行操作: 1. 获取dump文件:首先,通过Windbg获取应用程序的dump文件,dump文件保存了应用程序在发生时的内存和线程状态信息。 2. 加载dump文件:打开Windbg,选择“文件”菜单中的“打开转储文件”选项,然后选择要加载的dump文件。 3. 分析线程堆栈:使用Windbg命令"!analyze -v"分析线程堆栈。这个命令会提供线程堆栈的详细信息,包括当前线程和其它线程的调用栈。 4. 查找引起的资源:使用Windbg的命令"!locks"来查找引起的资源。这个命令会显示所有的、线程和资源之间的关系。通过查看这些信息,可以找到的根本原因。 5. 跟踪线程执行路径:通过Windbg的命令"kb"或"~*"查看所有线程的执行路径,定位到正在等待某个资源的线程。 6. 分析情况:根据线程堆栈和资源等信息,判断是什么原因导致了的发生,比如是否存在互斥的竞争、资源的有界性等问题。 7. 修复问题:根据分析结果,对问题进行修复,可能需要修改代码逻辑、优化资源的使用方式、增加资源数量等手段来解决。 需要注意的是,在使用Windbg进行排查时,需要对调试工具的使用有一定的经验和理解。同时,问题的排查也可能是一项复杂的任务,需要仔细的分析和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值