本文共 1942 字,大约阅读时间需要 6 分钟。
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
那么为什么会产生死锁呢?
1.因为系统资源不足。
2.进程运行推进的顺序不合适。
3.资源分配不当。
而产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
!locks 可以查看所有线程占用的锁信息,包含拥有锁的线程,以及有多少个线程在等待这把锁!
ntdll!RtlEnterCriticalSection的第一个参数就代表的互斥量或锁,可以通过!cs xxxxxxx 可以看到对应的互斥量信息(包含拥有这个锁的线程ID以及对应的信号量)
底层的临界区数据结构为_RTL_CRITICAL_SECTION,所以也可以通过dt命令去查看dt ntdll!_RTL_CRITICAL_SECTION 004030f4,获取到的信息和!cs 004030f4基本是一致的!
0:006> dt ntdll!_RTL_CRITICAL_SECTION +0x000 DebugInfo : Ptr64 _RTL_CRITICAL_SECTION_DEBUG +0x008 LockCount : Int4B +0x00c RecursionCount : Int4B +0x010 OwningThread : Ptr64 Void +0x018 LockSemaphore : Ptr64 Void +0x020 SpinCount : Uint8B
LockCount默认为-1,如果>=0,则表示有线程进入到临界区,要找出有多少线程正在等待进入临界区,可以:正在等待的线程数量=LockCount - RecursionCount + 1。
RecursionCount:表示同一个线程进入到临界区多少次,默认为0。
OwningThread:如果有线程进入到临界区,这是进入临界区的线程ID。
LockSemaphore:这是一个自动重置事件,当线程试图进入一个其他线程占用的临界区时,将会创建这个事件。
SpinCount:自旋锁的次数。
进一步看DebugInfo结构:
0:001> dt _RTL_CRITICAL_SECTION_DEBUG 02.ntdll!_RTL_CRITICAL_SECTION_DEBUG 03. +0x000 Type : Uint2B 04. +0x002 CreatorBackTraceIndex : Uint2B 05. +0x004 CriticalSection : Ptr32 _RTL_CRITICAL_SECTION 06. +0x008 ProcessLocksList : _LIST_ENTRY 07. +0x010 EntryCount : Uint4B 08. +0x014 ContentionCount : Uint4B 09. +0x018 Flags : Uint4B 10. +0x01c CreatorBackTraceIndexHigh : Uint2B 11. +0x01e SpareUSHORT : Uint2B
CriticalSection:在这个域上包含敢一个指针指向与这个结构相关的临界区。
ProcessLocksList:任何进程在操作系统中都将维护一张链表,其中包含了在这个进程中所有处于活跃状态的临界区,你可以通过这个节点中FLINK和BLINK来遍历进程中的临界区链表。
EntryCount:每当线程尝试进入一个已经被其他线程拥有的临界区并由此进入到等待状态,这个域的值都会被加1。
ntdll!NtWaitForSingleObject
NTSTATUS WINAPI NtWaitForSingleObject( _In_ HANDLE Handle, _In_ BOOLEAN Alertable, _In_ PLARGE_INTEGER Timeout );第一个参数句柄 可以通过!handle xxx f去查看详细的信息
?ntdll!__RtlUserThreadStart+0x20 可以查看对应的内存地址
转载地址:http://xtqxi.baihongyu.com/