事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(上)
用戶模式的線程同步機制效率高,如果需要考慮線程同步問題,應該首先考慮用戶模式的線程同步方法。但是,用戶模式的線程同步有限制,對于多個進程之間的線程同步,用戶模式的線程同步方法無能為力。這時,只能考慮使用內核模式。
Windows提供了許多內核對象來實現(xiàn)線程的同步。對于線程同步而言,這些內核對象有兩個非常重要的狀態(tài):“已通知”狀態(tài),“未通知”狀態(tài)(也有翻譯為:受信狀態(tài),未受信狀態(tài))。Windows提供了幾種內核對象可以處于已通知狀態(tài)和未通知狀態(tài):進程、線程、作業(yè)、文件、控制臺輸入/輸出/錯誤流、事件、等待定時器、信號量、互斥對象。
與事件EVENT的配合使用,能夠解決很多同步問題,也可以在數(shù)據(jù)達到某個狀態(tài)時啟動另一個線程的執(zhí)行,如報警。
EVENT 的幾個函數(shù):
1、CreateEvent和OpenEvent
HANDLE WINAPI CreateEvent(__in LPSECURITY_ATTRIBUTES lpEventAttributes, //表示安全控制,一般直接傳入NULL,表示不能被子進程繼承__in BOOL bManualReset, //參數(shù)確定事件是手動置位還是自動置位,傳入TRUE表示手動置位,傳入FALSE表示自動置位。__in BOOL bInitialState, //Event的初始狀態(tài), TRUE為觸發(fā),FALSE未觸發(fā)__in LPCTSTR lpName //Event object的名字,NULL表示沒名字(without a name) ); 要是CreateEvent創(chuàng)建的事件沒名字 這個函數(shù)就沒啥用了,不多做介紹,可查看msn。 HANDLE WINAPI OpenEvent( //獲得已經存在的Event的事件句柄__in DWORD dwDesiredAccess,__in BOOL bInheritHandle,__in LPCTSTR lpName //要打開的事件名字 );2、SetEvent,觸發(fā)事件
BOOL SetEvent(HANDLE hEvent);3、ResetEvent,使事件狀態(tài)設為未觸發(fā),如在創(chuàng)建事件時第二個參數(shù)為TRUE手動設置,則需要該函數(shù)去恢復事件為未觸發(fā)狀態(tài)。
BOOL SetEvent(HANDLE hEvent);4、PulseEvent, 如在創(chuàng)建事件時第二個參數(shù)為TRUE手動設置,其功能相當于SetEvent()后立即調用ResetEvent(),最好別用
BOOL PulseEvent(HANDLE hEvent)5、CloseHandle(),關閉該句柄。
事件是內核對象,事件分為手動置位事件和自動置位事件。事件Event內部它包含一個使用計數(shù)(所有內核對象都有),一個布爾值表示是手動置位事件還是自動置位事件,另一個布爾值用來表示事件有無觸發(fā)。事件可以由SetEvent()來觸發(fā),由ResetEvent()來設成未觸發(fā)。還可以由PulseEvent()來發(fā)出一個事件脈沖。
WaitForSingleObject()
在多線程下面,有時候我們會希望等待某一線程完成了再繼續(xù)做其他事情,要實現(xiàn)這個目的,可以使用Windows API函數(shù)WaitForSingleObject,或者WaitForMultipleObjects。這兩個函數(shù)都會等待Object被標為有信號(signaled)時才返回的。
那么,什么是信號呢?
簡單來說,Windows下創(chuàng)建的Object都會被賦予一個狀態(tài)量。如果Object被激活了,或者正在使用,那么該Object就是無信號,也就是不可用;另一方面,如果Object可用了,那么它就恢復有信號了。
這兩個函數(shù)的優(yōu)點是它們在等待的過程中會進入一個非常高效沉睡狀態(tài),只占用極少的CPU時間片。(這兩個函數(shù)都是在內核狀態(tài)下等待內核對象,不切換到用戶模式下,因而效率很高)
1、格式
DWORD WaitForSingleObject( HANDLE hHandle, DWORDdwMilliseconds);有兩個參數(shù),分別是THandle和Timeout(毫秒單位)。
如果想要等待一條線程,那么你需要指定線程的Handle,以及相應的Timeout時間。當然,如果你想無限等待下去,Timeout參數(shù)可以指定系統(tǒng)常量INFINITE。
WaitForSingleObject函數(shù)用來檢測hHandle事件的信號狀態(tài),當函數(shù)的執(zhí)行時間超過dwMilliseconds就返回,但如果參數(shù)dwMilliseconds為INFINITE時函數(shù)將直到相應時間事件變成有信號狀態(tài)才返回,否則就一直等待下去,直到WaitForSingleObject有返回值才執(zhí)行后面的代碼。此外,當dwMilliseconds設置為特殊值0時,測試hHandle核心對象是否被激發(fā),函數(shù)立即返回。
2. 使用對象
它可以等待如下幾種類型的對象:
Event(事件),Mutex(互斥量),Semaphore(信號量),Process(進程),Thread(線程),Change notification(變更通知),Console input(控制臺輸入),Job(可以被理解為進程的容器),Memory resource notification(內存資源通知),Waitable timer(等待定時器)
3. 返回類型
WAIT_ABANDONED:當hHandle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發(fā)此返回值。
4.示例:
#include <windows.h> #include <stdio.h> #include <iostream.h> //聲明函數(shù) 創(chuàng)建線程 DWORD WINAPI FunProc( LPVOID lpParameter); void main() { HANDLE hThread; hThread=CreateThread(NULL,0,FunProc,NULL,0,NULL); DWORD dwRet=WaitForSingleObject(hThread, 1); if(dwRet==WAIT_OBJECT_0) { printf("創(chuàng)建的線程執(zhí)行結束\n"); } if(dwRet==WAIT_TIMEOUT) { printf("等待超時\n"); } if(dwRet==WAIT_ABANDONED) { printf("Abandoned\n"); } CloseHandle(hThread); } DWORD WINAPI FunProc( LPVOID lpParameter ) { int i=1; for(; i<1000; i++) { printf("%d ", i); if(! (i%10)) printf("\n"); } return 0; }注意:不可以在WaitForSingleObject()之前執(zhí)行CloseHandle()否則會導致程序出錯!!
官方文檔解釋:
如果在wait操作仍處于暫掛狀態(tài)時關閉此句柄,則函數(shù)的行為將不明確。
WaitForMultipleObjecct()
WaitForMultipleObjects是Windows中的一個功能非常強大的函數(shù),幾乎可以等待Windows中的所有的內核對象
函數(shù)原型為:
DWORD WaitForMultipleObjects( DWORD nCount, // number of handles in the handle array CONST HANDLE *lpHandles, // pointer to the object-handle array BOOL fWaitAll, // wait flag DWORD dwMilliseconds // time-out interval in milliseconds );參數(shù)解析:
- DWORD 就是 Double Word, 每個word為2個字節(jié)的長度,DWORD雙字即為4個字節(jié),每個字節(jié)是8位。
nCount 指定列表中的句柄數(shù)量 最大值為MAXIMUM_WAIT_OBJECTS(64)
*lpHandles 句柄數(shù)組的指針。lpHandles為指定對象句柄組合中的第一個元素 HANDLE類型可以為(Event,Mutex,Process,Thread,Semaphore)數(shù)組
- bWaitAll 等待的類型,如果為TRUE,表示除非對象都發(fā)出信號,否則就一直等待下去;如果FALSE,表示任何對象發(fā)出信號即可
- dwMilliseconds指定要等候的毫秒數(shù)。如設為零,表示立即返回。如指定常數(shù)INFINITE,則可根據(jù)實際情況無限等待下去
函數(shù)的返回值有:
- WAIT_ABANDONED_0:所有對象都發(fā)出消息,而且其中有一個或多個屬于互斥體(一旦擁有它們的進程中止,就會發(fā)出信號)
- WAIT_TIMEOUT:對象保持未發(fā)信號的狀態(tài),但規(guī)定的等待超時時間已經超過
- WAIT_OBJECT_0:所有對象都發(fā)出信號
- WAIT_IO_COMPLETION:(僅適用于WaitForMultipleObjectsEx)由于一個I/O完成操作已作好準備執(zhí)行,所以造成了函數(shù)的返回
- 返回WAIT_FAILED則表示函數(shù)執(zhí)行失敗,會設置GetLastError
如bWaitAll為FALSE,那么返回結果相似,只是可能還會返回相對于WAIT_ABANDONED_0或WAIT_OBJECT_0的一個正偏移量,指出哪個對象是被拋棄還是發(fā)出信號。
WAIT_OBJECT_0是微軟定義的一個宏,你就把它看成一個數(shù)字就可以了。
例如,WAIT_OBJECT_0 + 5的返回結果意味著列表中的第5個對象發(fā)出了信號
如果程序中的nObjectWait是WAIT_OBJECT_0 + 5
int nIndex = nObjectWait - WAIT_OBJECT_0;就是說nIndex =5也就表示第5個對象發(fā)出了信號
示例:
當 bWaitAll參數(shù)為FALSE可以等待其中之一的事件
當要處理第一個事件時,你只需執(zhí)行SetEvent(m_hEvent[0]); 即可進入第一個事件的位置
當要執(zhí)行第二個事件時執(zhí)行SetEvent(m_hEvent[1]);
當 bWaitAll參數(shù)為TRUE等待所有的事件
DWORD WINAPI MyThreadProc(LPVOID lpParam) { while(TRUE) { //每次等500毫秒 int nIndex = WaitForMultipleObjects(2, pThis->m_hEvent, TRUE,500); if (WAIT_OBJECT_0 + 1<= nIndex <= WAIT_OBJECT_0) //所有事件發(fā)生 { //所有的信號量都有效時(事件都發(fā)生)其中之一無效。 }總結
以上是生活随笔為你收集整理的事件EVENT,WaitForSingleObject(),WaitForMultipleObjecct()和SignalObjectAndWait() 的使用(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: project项目管理案例_做总助,哪能
- 下一篇: 数据结构进阶篇-跳表