5.事件
在之前的課程里面講過,線程在進入臨界區之前會調用WaitForSingleObject或者WaitForMultipleOobjects,此時如果有信號,線程會從函數中退出并進入臨界區,如果沒有信號那么線程將自己掛入等待鏈表,然后將自己掛入等待網,最后切換線程。
其他線程在適當的時候,調用方法修改被等待對象的 SignalState 為有信號(不同的等待對象,會調用不同的函數),并將等待該對象的其他線程從等待鏈表中摘掉,這樣,當前線程便會在 WaitForSingleObject 或者 WaitForMultipleObjects 恢復執行(在哪切換在哪開始執行),如果符合喚醒條件,此時會修改 SignalState 的值,并將自己從等待網上摘下來,此時的線程才是真正的喚醒。
被等待對象不同,主要在2個點上會有差異:
創建事件對象:信號
測試代碼:
HANDLE g_hEvent;VOID WINAPI ThreadProc1(LPVOID text) {::WaitForSingleObject(g_hEvent, INFINITE);printf("ThreadProc1函數執行...\n"); }VOID WINAPI ThreadProc2(LPVOID text) {::WaitForSingleObject(g_hEvent, INFINITE);printf("ThreadProc2函數執行...\n"); }VOID WINAPI ThreadProc3(LPVOID text) {::WaitForSingleObject(g_hEvent, INFINITE);printf("ThreadProc3函數執行...\n"); }int main() {//默認安全屬性 對象類型 初始狀態 名字g_hEvent = ::CreateEvent(NULL, false, FALSE, NULL);HANDLE hThread[3];//創建3個線程hThread[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0, NULL);hThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0, NULL);hThread[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc3, NULL, 0, NULL);//設置事件為已通知SetEvent(g_hEvent);//等待線程結束 銷毀內核對象WaitForMultipleObjects(3, hThread, TRUE, INFINITE);CloseHandle(hThread[0]);CloseHandle(hThread[1]);CloseHandle(hThread[2]);CloseHandle(g_hEvent);getchar();return 0; } //參數1:默認安全屬性 //參數2:對象類型 //參數3:初始化的事件狀態 //參數4:名稱 CreateEvent(NULL, TRUE, FALSE, NULL);//如果參數2為true 通知類型對象,false 事件同步對象 //如果參數3為false未通知,true已通知_DISPATCHER_HEADER +0x000 Type //對應上面第2個參數 +0x001 Absolute +0x002 Size +0x003 Inserted +0x004 SignalState //對應上面第3個參數 +0x008 WaitListHeadSetEvent函數分析
SetEvent對應的內核函數: KeSetEvent
還是這個偽代碼
while(true)//每次線程被其他線程喚醒,都要進入這個循環{if(符合激活條件)//1超時 2等待對象SignalState > 0{//1修改SignalState //2退出循環}else//SignalState不大于0 也沒超時{if(第一次執行){//將當前線程的等待塊掛到等待對象的鏈表 (WaitListHead) 中;//將自己掛入等待隊列(KiaitListHead)//切換線程...再次獲得CPU時,從這里開始執行}}} 1)線程將自己+5c位置清0 2)釋放_KWAIT_BLOCK所占內存如果事件類型為TRUE,跳到這
總結
- 上一篇: 4.WaitForSingleObjec
- 下一篇: 6.信号量