首先介紹CreateEvent是創建windows事件的意思,作用主要用在判斷線程退出,線程鎖定方面.
CreateEvent
函功能描述:創建或打開一個命名的或無名的事件對象.
EVENT有兩種狀態:發信號,不發信號。
SetEvent/ResetEvent分別將EVENT置為這兩種狀態分別是發信號與不發信號。
WaitForSingleObject()等待,直到參數所指定的OBJECT成為發信號狀態時才返回,OBJECT可以是EVENT,也可以是其它內核對象。
當你創建一個線程時,其實那個線程是一個循環,不像上面 那樣只運行一次的。這樣就帶來了一個問題,在那個死循環里要找到合適的條件退出那個死循環,那么是怎么樣實現它的呢?在Windows里往往是采用事件的 方式,當然還可以采用其它的方式。在這里先介紹
采用事件的方式來通知從線程運行函數退出來,它的實現原理是這樣,在那個死循環里不斷地使用 WaitForSingleObject函數來檢查事件是否滿足,如果滿足就退出線程,不滿足就繼續運行。當在線程里運行阻塞的函數時,就需要在退出線程 時,先要把阻塞狀態變成
非阻塞狀態,比如使用一個線程去接收網絡數據,同時使用阻塞的SOCKET時,那么要先關閉SOCKET,再發送事件信號,才可以 退出線程的。
當然我感覺重要應用方面還是用來鎖定,實現所謂的pv功能。
下面介紹函數功能,參數等
1.CreateEvent
函數功能描述:創建或打開一個命名的或無名的事件對象 函數原型: HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全屬性 BOOL bManualReset, // 復位方式 BOOL bInitialState, // 初始狀態 LPCTSTR lpName // 對象名稱 ); 參數: lpEventAttributes: [輸入]一個指向SECURITY_ATTRIBUTES結構的指針,確定返回的句柄是否可被子進程繼承。如果lpEventAttributes是NULL,此句柄不能被繼承。 Windows NT/2000:lpEventAttributes的結構中的成員為新的事件指定了一個安全符。如果lpEventAttributes是NULL,事件將獲得一個默認的安全符。 bManualReset: [輸入]指定將事件對象創建成手動復原還是自動復原。如果是TRUE,那么必須用ResetEvent函數來手工將事件的狀態復原到無信號狀態。如果設置為FALSE,當事件被一個等待線程釋放以后,系統將會自動將事件狀態復原為無信號狀態。 bInitialState: [輸入]指定事件對象的初始狀態。如果為TRUE,初始狀態為有信號狀態;否則為無信號狀態。 lpName: [輸入]指定事件的對象的名稱,是一個以0結束的字符串指針。名稱的字符格式限定在MAX_PATH之內。名字是對大小寫敏感的。 如果lpName指定的名字,與一個存在的命名的事件對象的名稱相同,函數將請求EVENT_ALL_ACCESS來訪問存在的對象。這時候,由於 bManualReset和bInitialState參數已經在創建事件的進程中設置,這兩個參數將被忽略。如果lpEventAttributes是 參數不是NULL,它將確定此句柄是否可以被繼承,但是其安全描述符成員將被忽略。 如果lpName為NULL,將創建一個無名的事件對象。 如果lpName的和一個存在的信號、互斥、等待計時器、作業或者是文件映射對象名稱相同,函數將會失敗,在GetLastError函數中將返回ERROR_INVALID_HANDLE。造成這種現象的原因是這些對象共享同一個命名空間。 終端服務(Terminal Services):名稱中可以加入"Global\"或是"Local\"的前綴,這樣可以明確的將對象創建在全局的或事務的命名空間。名稱的其它部分 除了反斜杠(\),可以使用任意字符。詳細內容可參考Kernel Object Name Spaces。 Windows 2000:在Windows 2000系統中,沒有終端服務運行,"Global\"和"Local\"前綴將被忽略。名稱的其它部分除了反斜杠(\),可以使用任意字符。 Windows NT 4.0以及早期版本, Windows 95/98:名稱中除了反斜杠(\),可以使用任意字符。 返回值: 如果函數調用成功,函數返回事件對象的句柄。如果對於命名的對象,在函數調用前已經被創建,函數將返回存在的事件對象的句柄,而且在GetLastError函數中返回ERROR_ALREADY_EXISTS。 如果函數失敗,函數返回值為NULL,如果需要獲得詳細的錯誤信息,需要調用GetLastError。 備注: 調用CreateEvent函數返回的句柄,該句柄具有EVENT_ALL_ACCESS權限去訪問新的事件對象,同時它可以在任何有此事件對象句柄的函數中使用。 在調用的過程中,所有線程都可以在一個等待函數中指定事件對象句柄。當指定的對象的狀態被置為有信號狀態時,單對象等待函數將返回。 對於多對象等待函數,可以指定為任意或所有指定的對象被置為有信號狀態。當等待函數返回時,等待線程將被釋放去繼續運行。 初始狀態在bInitialState參數中進行設置。使用SetEvent函數將事件對象的狀態置為有信號狀態。使用ResetEvent函數將事件對象的狀態置為無信號狀態。 當一個手動復原的事件對象的狀態被置為有信號狀態時,該對象狀態將一直保持有信號狀態,直至明確調用ResetEvent函數將其置為無符號狀態。 當事件的對象被置為有信號狀態時,任意數量的等待中線程,以及隨后開始等待的線程均會被釋放。 當一個自動復原的事件對象的狀態被置為有信號狀態時,該對象狀態將一直保持有信號狀態,直至一個等待線程被釋放;系統將自動將此函數置為無符號狀態。如果沒有等待線程正在等待,事件對象的狀態將保持有信號狀態。 多個進程可持有同一個事件對象的多個句柄,可以通過使用此對象來實現進程間的同步。下面的對象共享機制是可行的: ·在CreateEvent函數中,lpEventAttributes參數指定句柄可被繼承時,通過CreateProcess函數創建的子進程繼承的事件對象句柄。 ·一個進程可以在DuplicateHandle函數中指定事件對象句柄,從而獲得一個復制的句柄,此句柄可以被其它進程使用。 ·一個進程可以在OpenEvent或CreateEvent函數中指定一個名字,從而獲得一個有名的事件對象句柄。 使用CloseHandle函數關閉句柄。當進程停止時,系統將自動關閉句柄。當最后一個句柄被關閉后,事件對象將被銷毀。 使用環境: Windows NT/2000:需要3.1或更高版本 Windows 95/98:需要Windows 95或更高版本 頭文件:定義在Winbase.h;需要包含 Windows.h。 導入庫:user32.lib Unicode:在Windows NT/2000中,以 Unicode 和 ANSI 執行 一個Event被創建以后,可以用OpenEvent()API來獲得它的Handle,用CloseHandle() 來關閉它,用SetEvent()或PulseEvent()來設置它使其有信號,用ResetEvent() 來使其無信號,用WaitForSingleObject()或WaitForMultipleObjects()來等待 其變為有信號.
PulseEvent()是一個比較有意思的使用方法,正如這個API的名字,它使一個Event 對象的狀態發生一次脈沖變化,從無信號變成有信號再變成無信號,而整個操作是原子的. 對自動復位的Event對象,它僅釋放第一個等到該事件的thread(如果有),而對於 人工復位的Event對象,它釋放所有等待的thread. |
2. WaitForSingleObject的用法
WaitForSingleObject的用法
DWORD WINAPI WaitForSingleObject(
WAIT_ABANDONED0x00000080L
|
The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread and the mutex state is set to nonsignaled.
If the mutex was protecting persistent state information, you should check it for consistency.
|
WAIT_OBJECT_00x00000000L
|
The state of the specified object is signaled.
|
WAIT_TIMEOUT0x00000102L
|
The time-out interval elapsed, and the object's state is nonsignaled.
|
WAIT_FAILED(DWORD)0xFFFFFFFF
|
The function has failed. To get extended error information, call
GetLastError.
|
UINT CFlushDlg::MyThreadProc( LPVOID pParam ) { WaitForSingleObject(g_event,INFINITE); For(;;) { …………. } return 0; }
UINT CFlushDlg::MyThreadProc( LPVOID pParam ) { while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0) { //…… } return 0; }