4.WaitForSingleObject函式分析
阿新 • • 發佈:2018-12-17
無論可等待物件是何種型別,執行緒都是通過:
WaitForSingleObject WaitForMultipleObjects
進入等待狀態的,這兩個函式是理解執行緒等待與喚醒進位制的核心
WaitForSingleObject引數說明
WaitForSingleObject對應的核心函式:
NTSTATUS stdcall NtWaitForSingleObject
(
HANDLE Handle,
BOOLEAN Alertable,
PLARGE_INTEGER Timeout
)
Handle 使用者層傳遞的等待物件的控制代碼 (具體細節參加控制代碼表專題)
Alertable 對應 KTHREAD 結構體的 Alertable 屬性如果為1在插入使用者APC時,該執行緒將被吵醒
Timeout 超時時間
NtWaitForSingleObject
- 呼叫ObReferenceObjectByHandle函式,通過物件控制代碼找到等待物件結構體地址。
- 呼叫KeWaitForSingleObject函式,進入關鍵迴圈。
KeWaitForSingleObject:上半部分
!process 89316020
dt _KTHREAD 892db020
dt _KWAIT_BLOCK 892db020+70
每個等待塊大小為0x18。 如果等待3個物件的話它就會佔用前3個等待塊,最後一個是給定時器用的。 如果你有4個等待物件它就不會用這個位置了,它會一次性分配新的空間。
- 向KTHREAD(+70)位置的等待塊賦值。
- 如果超時時間不為0, KTHREAD(+70)第四個等待塊與第一個等待塊關聯起來:第一個等待塊指向第四個等待塊,第四個等待塊指向第一個等待塊。
- KTHREAD(+5C)指向第一個KWAIT_BLOCK
- 進入關鍵迴圈
KeWaitForSingleObject的關鍵迴圈
while(true)//每次執行緒被其他執行緒喚醒,都要進入這個迴圈
{
if(符合啟用條件)//1超時 2等待物件SignalState > 0
{
//1修改SignalState
//2退出迴圈
}
else//SignalState不大於0 也沒超時
{
if (第一次執行)
{
//將當前執行緒的等待塊掛到等待物件的連結串列 (WaitListHead) 中;
//將自己掛入等待佇列(KiaitListHead)
//切換執行緒...再次獲得CPU時,從這裡開始執行
}
}
}
1)執行緒將自己+5c位置清0
2)釋放_KWAIT_BLOCK所佔記憶體
WaitForSingleObject引數說明
kd> dt _DISPATCHER_HEADER
nt!_DISPATCHER_HEADER
+0x000 Type //型別
+0x001 Absolute
+0x002 Size
+0x003 Inserted
+0x004 SignalState //是否有訊號 (值大於0就是有訊號)
+0x008 WaitListHead //雙向連結串列頭,圈著所有等待塊
不同的等待物件,用不同的方法來修改_DISPATCHER_HEADER(SignalState)比如:如果可等待物件是EVENT,其他執行緒通常使用SetEvent來設定SignalState= 1並且,將正在等待該物件的其他執行緒喚醒,也就是從等待連結串列(KiWaitListHead)中摘出來。但是, SetEvent函式並不會將執行緒從等待網上摘下來,是否要下來,由當前執行緒自己來決定。
關於強制喚醒 在APC專題講過,當我們插入一個使用者APC時(Alertable=1),當前執行緒是可以被喚醒的,但並不是真正的喚醒。 因為,如果當前的執行緒在等待網上,執行完使用者APC後,仍然要進入等待狀態。