標籤:createevent setevent resetevent waitforsingleobject
事件對象就像一個開關:它只有兩種狀態---開和關。當一個事件處於”開”狀態,我們稱其為”有訊號”,否則稱為”無訊號”。可以在一個線程的執行函數中建立一個事件對象,然後觀察它的狀態,如果是”無訊號”就讓該線程睡眠,這樣該線程佔用的CPU時間就比較少。
產生事件對象的函數如下:
(1)CreateEvent
函數原型:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全屬性
BOOL bManualReset, // 複位方式
BOOL bInitialState, // 初始狀態
LPCTSTR lpName // 對象名稱
);
該函數建立一個Event同步對象,如果CreateEvent調用成功的話,會返回新產生的對象的控制代碼,否則返回NULL。
lpEventAttributes:一般為NULL
bManualReset:指定將事件對象建立成手動複原還是自動複原。如果是TRUE(手動),那麼就算等待線程處理了,必須用ResetEvent函數來手工才能將事件的狀態複原到無訊號狀態。如果設定為FALSE(自動),當事件被一個等待線程處理並釋放以後,系統會自動將事件狀態複原為無訊號狀態。所以兩者可用於不同的場合,自動複位的需要每次的事件訊號才會執行,而手動複位的則可以一直運行。
bInitialState:指定事件對象的初始狀態。如果為TRUE,初始狀態為有訊號狀態;否則為無訊號狀態。
lpName:指定事件的對象的名稱,在OpenEvent函數中可能使用。
範例程式碼:// 建立一個有名的,不能被繼承的,手動複原,初始狀態是無訊號狀態的事件對象:
Handle h = CreateEvent(NULL,TRUE,FALSE,“MyEvent”);
一個Event被建立以後,可以用OpenEvent()API來獲得它的Handle,用CloseHandle()來關閉它,用SetEvent()或PulseEvent()來設定它使其有訊號,用ResetEvent()來使其無訊號,用WaitForSingleObject()或WaitForMultipleObjects()來等待其變為有訊號.。
(2)SetEvent
函數原型:
BOOL WINAPI SetEvent(
__in HANDLE hEvent
);
設定事件的狀態為有標記。如果事件建立時是手工的,此事件將保持有標記直到調用ResetEvent。如果事件是自動的,此事件將保持有標記,直到一個線程被釋放,系統將設定事件的狀態為無標記。
(3)ResetEvent
函數原型:
BOOL ResetEvent(
HANDLE hEvent
);
hEvent 指向事件對象的控制代碼,由 CreateEvent or OpenEvent 函數返回。這個控制代碼需要擁有EVENT_MODIFY_STATE 存取權限。函數成功,返回非0值,否則返回0值,可以調用GetLastError得到錯誤的詳細資料。
這個函數用於手動重設事件對象。手動重設的對象線上程釋放後必須手動置為無訊號狀態。自動重設的事件對象在一個等待它成功的線程釋放後會自動變為無訊號狀態。 重設一個無訊號的事件對象沒有任何效果。
(4)WaitForSingleObject
函數原型:
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
參數hHandle是一個事件的控制代碼,第二個參數dwMilliseconds是時間間隔。如果事件是有訊號狀態返回WAIT_OBJECT_0,如果事件超過dwMilliseconds值但事件還是無訊號狀態,則返回WAIT_TIMEOUT。之前線程會一直阻塞程式在該語句處。
舉例:
#include <windows.h>#include <iostream>#include <string>#include <vector>using namespace std;//通過事件得知另一個線程的內部狀態//例:線程內部有三種狀態:起床 吃飯 上班HANDLE getupHandle;HANDLE breakfastHandle;HANDLE workHandle;vector<string> stateTexts;DWORD WINAPI Worker(LPVOID n);int main(){stateTexts.reserve(3);//容器預留空間getupHandle = CreateEvent(NULL, TRUE, FALSE, NULL);//手動,無訊號breakfastHandle = CreateEvent(NULL, TRUE, FALSE, NULL);workHandle = CreateEvent(NULL, TRUE, FALSE, NULL);DWORD threadId;HANDLE threadHandle = CreateThread(NULL,0,Worker,//線程入口函數0,0,&threadId);WaitForSingleObject(getupHandle, INFINITE);cout << stateTexts[0] << endl;WaitForSingleObject(breakfastHandle, 3000);cout << stateTexts[1] << endl;WaitForSingleObject(workHandle, INFINITE);cout << stateTexts[2] << endl;CloseHandle(threadHandle);CloseHandle(getupHandle);CloseHandle(breakfastHandle);CloseHandle(workHandle);system("pause");}DWORD WINAPI Worker(LPVOID n){stateTexts.push_back("GetUp");SetEvent(getupHandle);stateTexts.push_back("Breakfast");ResetEvent(breakfastHandle);stateTexts.push_back("Work");SetEvent(workHandle);return 0;}運行結果:
先顯示 GetUp,等待3000ms後顯示Breakfast,接著馬上顯示Work
由於getupHandle和workHandle是設定為有訊號的,它們的WaitForSingleObject直接有返回值
breakfastHandle設定為無訊號的,它的WaitForSingleObject要等待定時完成才有返回值