日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析

發(fā)布時(shí)間:2025/3/21 windows 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Windows事件等待學(xué)習(xí)筆記(三)—— WaitForSingleObject函數(shù)分析

    • 要點(diǎn)回顧
    • WaitForSingleObject
    • NtWaitForSingleObject
    • KeWaitForSingleObject:上半部分
      • 關(guān)鍵循環(huán)
      • 總結(jié)
      • 關(guān)于強(qiáng)制喚醒
      • 實(shí)驗(yàn):證明等待塊與等待塊表的關(guān)系
        • 第一步:編譯并運(yùn)行以下代碼
        • 第二步:再WinDbg中找到該進(jìn)程
        • 第三步:查看線程信息

要點(diǎn)回顧

無論可等待對(duì)象是何種類型,線程都是通過 WaitForSingleObject 和 WaitForMultipleObjects進(jìn)入等待狀態(tài)的,這兩個(gè)函數(shù)是理解線程等待與喚醒進(jìn)制的核心

WaitForSingleObject

DWORD WaitForSingleObject(HANDLE hHandle, // handle to objectDWORD dwMilliseconds // time-out interval);

對(duì)應(yīng)的內(nèi)核函數(shù):NtWaitForSingleObject

NTSTATUS __stdcall NtWaitForSingleObject(HANDLE Handle, //用戶層傳遞的等待對(duì)象的句柄(具體細(xì)節(jié)參加句柄表專題)BOOLEAN Alertable, //對(duì)應(yīng)KTHREAD結(jié)構(gòu)體的Alertable屬性//如果為1 在插入用戶APC時(shí),該線程將被吵醒 PLARGE_INTEGER Timeout //超時(shí)時(shí)間);

NtWaitForSingleObject

  • 調(diào)用ObReferenceObjectByHandle函數(shù),通過對(duì)象句柄找到等待對(duì)象結(jié)構(gòu)體地址
  • 調(diào)用KeWaitForSingleObject函數(shù),進(jìn)入關(guān)鍵循環(huán)
  • KeWaitForSingleObject:上半部分

  • 準(zhǔn)備等待塊,當(dāng)?shù)却龑?duì)象少于四個(gè)時(shí),并不為等待對(duì)象分配新的空間,而是向 _KTHREAD(+70) 位置的等待塊賦值,_KTHREAD(+5C) 指向第一個(gè)等待塊的位置
    注意:無論使用與否,_KTHREAD(+70)的第四個(gè)等待塊被定時(shí)器占據(jù),如果用的話,將會(huì)把定時(shí)器與第一個(gè)等待塊相關(guān)聯(lián)
  • 如果超時(shí)時(shí)間不為0KTHREAD(+70) 第四個(gè)等待塊與第一個(gè)等待塊關(guān)聯(lián)起來:
    第一個(gè)等待塊指向第四個(gè)等待塊,第四個(gè)等待塊指向第一個(gè)等待塊。
  • KTHREAD(+5C) 指向第一個(gè) _KWAIT_BLOCK
  • 進(jìn)入關(guān)鍵循環(huán)
  • 關(guān)鍵循環(huán)

  • 判斷當(dāng)前被等待對(duì)象是否有信號(hào)
    (每一個(gè)線程等待對(duì)象是通過等待塊進(jìn)行關(guān)聯(lián)的,但是對(duì)象有一個(gè)條件:至少有一個(gè)成員為 _DISPATCHER_HEADER 結(jié)構(gòu)體)_DISPATCHER_HEADER+0x000 Type //類型 可通過IDA或WinDbg查看所需對(duì)象的類型//IDA:分析二進(jìn)制代碼//WinDbg:Wait一個(gè)對(duì)象,然后進(jìn)行查看+0x001 Absolute +0x002 Size +0x003 Inserted +0x004 SignalState //是否有信號(hào)(大于0表示有信號(hào)) +0x008 WaitListHead //雙向鏈表頭 圈著所有等待塊
  • 第一次循環(huán)時(shí),若等待對(duì)象未超時(shí),但是有信號(hào),就不會(huì)將當(dāng)前線程的等待塊掛到等待對(duì)象的鏈表(WaitListHead)中,直接修改信號(hào)的值,退出循環(huán)
  • 第一次循環(huán)時(shí),若等待對(duì)象未超時(shí),但是無信號(hào),就將當(dāng)前線程的等待塊掛到等待對(duì)象的鏈表(WaitListHead)中,將線程自己掛入等待隊(duì)列(KiWaitListHead),切換線程
  • 當(dāng)線程將自己掛入等待隊(duì)列后,需要等待另一個(gè)線程將自己?jiǎn)拘?#xff08;設(shè)置等待對(duì)象信號(hào)量>0),當(dāng)其它線程將自己?jiǎn)拘押?#xff0c;再沿著等待網(wǎng)找是誰喚醒了自己,找到了之后將自己從等待鏈表(KiWaitListHead)中摘出,但并未從等待網(wǎng)中摘出
  • 線程從哪里切換就從哪里復(fù)活
  • 完整邏輯

    while(true)//每次線程被其他線程喚醒,都要進(jìn)入這個(gè)循環(huán) {if(符合激活條件)//1、超時(shí) 2、等待對(duì)象SignalState>0 {//1) 修改SignalState//2) 退出循環(huán)}else{if(第一次執(zhí)行)將當(dāng)前線程的等待塊掛到等待對(duì)象的鏈表(WaitListHead);//將自己掛入等待隊(duì)列(KiWaitListHead)//切換線程...再次獲得CPU時(shí),從這里開始執(zhí)行} }

    退出循環(huán)

  • 線程將自己+5C的位置清0(WaitBlockList)
  • 釋放 _KWAIT_BLOCK 所占用的內(nèi)存
  • 總結(jié)

  • 不同的等待對(duì)象,用不同的方法來修改 _DISPATCHER_HEADER->SignalState

  • 如果可等待對(duì)象是EVENT,其他線程通常使用SetEvent來設(shè)置SignalState = 1,并且,將正在等待該對(duì)象的其他線程喚醒,也就是從等待鏈表(KiWaitListHead)中摘出來,此時(shí)線程臨時(shí)復(fù)活

  • SetEvent函數(shù)并不會(huì)將線程從等待網(wǎng)上摘下來,是否要下來,由當(dāng)前線程自己來決定

  • 若使用SetEvent這種函數(shù)直接將線程從等待網(wǎng)上摘下來,將會(huì)非常麻煩,因?yàn)榭赡苡蟹浅6嗟木€程在等待一個(gè)對(duì)象,無法判斷該將誰摘下(一個(gè)也線程可能等待著多個(gè)對(duì)象)

    比如線程A線程B同時(shí)在等待著一個(gè)對(duì)象,這時(shí)如果有線程C調(diào)用了SetEvent(將等待對(duì)象的信號(hào)量置1),線程A線程B會(huì)被臨時(shí)喚醒(從KiWaitLkistHead摘下),并行進(jìn)入關(guān)鍵循環(huán),假設(shè)線程A先運(yùn)行,線程A會(huì)設(shè)置等待對(duì)象信號(hào)量<=0,然后將自己從等待網(wǎng)上摘下來,此時(shí)線程A徹底復(fù)活。線程B再去判斷等待對(duì)象是否有信號(hào)量時(shí),已經(jīng)沒有信號(hào)量了,這時(shí)線程B會(huì)將自己重新掛入等待鏈表中(有點(diǎn)繞,慢慢理解)

  • 不同對(duì)象調(diào)用API修改信號(hào)個(gè)數(shù)只在細(xì)節(jié)上有差異,本質(zhì)上都是一樣的

  • 關(guān)于強(qiáng)制喚醒

    描述:在APC專題中講過,當(dāng)插入一個(gè)用戶APC時(shí)(Alertable=1),當(dāng)前線程是可以被喚醒的,但并不是真正的喚醒。因?yàn)槿绻?dāng)前的線程在等待網(wǎng)上,執(zhí)行完用戶APC后,線程仍然要進(jìn)入等待狀態(tài)

    實(shí)驗(yàn):證明等待塊與等待塊表的關(guān)系

    第一步:編譯并運(yùn)行以下代碼

    #include <stdio.h> #include <windows.h>HANDLE hEvent[3];DWORD WINAPI ThreadProc(LPVOID lpParamter) {::WaitForSingleObject(hEvent[0], -1);printf("ThreadProc函數(shù)執(zhí)行\(zhòng)n");return 0; }int main(int argc, char* argv[]) {hEvent[0] = ::CreateEvent(NULL, TRUE, FALSE, NULL); //創(chuàng)建可等待對(duì)象::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0, NULL);getchar();return 0; }

    第二步:再WinDbg中找到該進(jìn)程



    第三步:查看線程信息


    《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結(jié)

    以上是生活随笔為你收集整理的Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。