1、爲什麼要由互斥體:等待對象被遺棄
互斥體(MUTANT)與事件(EVENT)和信號量(SEMAPHORE)一樣,都可以用來進行線程同步。
但需要明確的是,這幾個對象都是內核對象,這就意味着,通過這幾個對象可以用來進行跨進程間的線程同步控制。比如:
A進程中的X線程
B進程中的Y線程
都等待Z對象
極端情況:
如果B進程裏的Y線程還沒來得及調用修改SignalState的函數(如SetEvent),那麼等待對象Z將被遺棄,這也就意味着X進程中的線程將永遠等待下去。
這種極端的情況,時間和信號量是無法解決的。如果用互斥體,B進程中的Y線程沒有來得及修改,系統會幫忙修改。
2、爲什麼要由互斥體:重入
如果需要多次重入臨界區,用互斥體就不會死鎖。互斥體與時間和信號量的第二個區別就是允許重複進入臨界區。
爲什麼互斥體可以重複進入臨界區。
3、MUTANT結構體介紹
nt!_KMUTANT
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListEntry : _LIST_ENTRY
+0x018 OwnerThread : Ptr32 _KTHREAD
+0x01c Abandoned : UChar
+0x01d ApcDisable : UChar
MutantListEntry :
擁有互斥體線程( KTHREAD +0x010 MutantListHead : _LIST_ENTRY)是個鏈表頭,牽着所有線程。
OwnerThread :
正在擁有互斥體的線程
Abandoned :
是否已被放棄不用
ApcDisable :
是否禁用內核APC
4、CreateMutex函數
HANDLE CreateMutex(LPSECURITY_ATTRIBUTE SlpMutexAttributes,//指向安全屬性的指針
BOOL bInitailOwner, //初始化互斥對象的所有者
LPCTSTR lpName //指向互斥體對象名的指針
);
CreateMutex–>NtCreateMutant(內核函數)–>KeInitializeMutant(內核函數)
初始化MUTANT結構體:
MUTANT.Header.Type = 2;
MUTANT.Header.SignalState = bInitailOwner ? 0 : 1;
MUTANT.OwnerThread = 當前線程 or NULL;
MUTANT.Abandoned = 0;
MUTANT.ApcDisable= 0;
bInitailOwner == TRUE 將當前的互斥體掛入噹噹前線程的互斥體鏈表中( +0x010 MutantListHead : _LIST_ENTRY)
5、ReleaseMutex函數
BOOL WINAPI ReleaseMutex(HANDLE hMutex);
ReleaseMutex–>NtReleaseMutant–>KeReleaseMutant
正常調用時:
MUTANT.Header.SignalState++;
如果SignalState = 1說明其他進程可用了,將該互斥體從線程鏈表中移除。
6、如何解決重入的問題
nt!_KMUTANT
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListEntry : _LIST_ENTRY
+0x018 OwnerThread : Ptr32 _KTHREAD
+0x01c Abandoned : UChar
+0x01d ApcDisable : UChar
OwnerThread:正在擁有互斥體的線程
(參見KeWaitForSingleObject)
7、如何解決等待對象被遺棄的問題
nt!_KMUTANT
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListEntry : _LIST_ENTRY
+0x018 OwnerThread : Ptr32 _KTHREAD
+0x01c Abandoned : UChar
+0x01d ApcDisable : UChar
MutantListEntry :
擁有互斥體線程( KTHREAD +0x010 MutantListHead : _LIST_ENTRY)是個鏈表頭,牽着所有線程。
Abandoned :
是否已被放棄不用
8、如何解決等帶對象被遺棄的問題
MmUnloadSystemImage -->KeReleaseMutant(X, Y , Abandon, Z)//是否被丟棄
if(Abandon == false)//正常被調用
{
MUTANT.Header.SignalState++;
}
else
{
MUTANT.Header.SignalState = 1;
MUTANT.OwnerThread = NULL;
}
if( MUTANT.Header.SignalState == 1)
{
MUTANT.OwnerThread = NULL;
//從當前線程互斥體鏈表中將當前互斥體移除
}
(參見KeReleaseMutant)