Event 方式是最具彈性的同步機制,由於他的狀態徹底由你去決定,不會像 Mutex 和 Semaphores 的狀態會由相似:WaitForSingleObject 一類的函數的調用而改變,因此你能夠精確的告訴 Event 對象該作什麼事?以及何時去作!ios
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName // object name
);
lpEventAttributes : 一個指向SECURITY_ATTRIBUTES結構的指針,肯定返回的句柄是否可被子進程繼承。若是lpEventAttributes是NULL,此句柄不能被繼承。
bManualReset : 建立一我的工重置的事件(TRUE)使用ResetEvent()手動重置爲無信號狀態,
建立一個自動重置的事件(FALSE)。當一個等待線程被釋放時,自動重置狀態爲無信號狀態。
bInitialState : 用於指明該事件是要初始化爲已通知狀態(TRUE)仍是未通知狀態(FALSE) windows
bManualReset爲TRUE時: 人工重置事件,當一個等待線程被釋放時,必須使用ResetEvent()手動重置爲無型號狀態安全
當人工重置的事件獲得通知時,等待該事件的全部線程均變爲可調度線程。app
bManualReset爲FALSE時: 自動重置事件,當一個等待線程被釋放時,自動重置狀態爲無信號狀態
當自動重置的事件獲得通知時,等待該事件的線程中只有一個線程變爲可調度線程。函數
自動重置事件(一般沒有必要爲自動重置的事件調用ResetEvent函數)。 測試
使用方法:
一、建立一個事件對象:CreateEvent;
二、打開一個已經存在的事件對象:OpenEvent;
三、得到事件的佔有權:WaitForSingleObject 等函數(可能形成阻塞);
四、釋放事件的佔有權(設置爲激發(有信號)狀態,以讓其餘等待中的線程甦醒):SetEvent;
五、手動置爲非激發(無信號)狀態:ResetEvent
六、關閉事件對象句柄:CloseHandle;spa
固有特色(優勢+缺點):
一、是一個系統核心對象,因此有安全描述指針,用完了要 CloseHandle 關閉句柄,這些是內核對象的共同特徵;
二、由於是核心對象,因此執行速度稍慢(固然只是相比較而言);
三、由於是核心對象,並且能夠命名,因此能夠跨進程使用;
四、一般被用於 overlapped I/O 或被用來設計某些自定義的同步對象。線程
相關函數:設計
BOOL WINAPI SetEvent( __in HANDLE hEvent ); 把event對象設置爲激活狀態
BOOL WINAPI ResetEvent( __in HANDLE hEvent ); 把event對象設置爲非激活狀態
BOOL WINAPI PulseEvent( __in HANDLE hEvent );
若是是一我的工重置事件:把event對象設置爲激活狀態,喚醒「全部」等待中的線程,而後event恢復爲非激活狀態
若是是一個自動重置事件:把event對象設置爲激活狀態,喚醒 「一個」等待中的線程,而後event恢復爲非激活狀態
下面主要演示一下采用CreateEvent實現線程同步。指針
例子很簡單,主要測試CreateEvent中bManualReset 和 bInitialState 參數的取值在線程調用中信號狀態的狀況。
一、bManualReset:TRUE
bInitialState:TRUE
CreateEvent(NULL, TRUE, TRUE, NULL); //人工重置事件:使用手動重置爲無信號狀態,初始化時有信號狀態
#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI ThreadProc1(LPVOID lpParam); DWORD WINAPI ThreadProc2(LPVOID lpParam); HANDLE hEvent = NULL; HANDLE hThread1 = NULL; HANDLE hThread2 = NULL; int main(int argc, char *args[]) { hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); //使用手動重置爲無信號狀態,初始化時有信號狀態 hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc1, NULL, 0,NULL); hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc2, NULL, 0,NULL); WaitForSingleObject( hThread1, INFINITE ); WaitForSingleObject( hThread2,INFINITE ); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程1被調用!\n";
ResetEvent(hEvent); } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程2被調用!\n";
ResetEvent(hEvent); } return 0; }
二、bManualReset:TRUE
bInitialState:FALSE
CreateEvent(NULL, TRUE, FALSE, NULL);//人工重置事件:使用手動重置爲無信號狀態,初始化時爲無信號狀態
#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI ThreadProc1(LPVOID lpParam); DWORD WINAPI ThreadProc2(LPVOID lpParam); HANDLE hEvent = NULL; HANDLE hThread1 = NULL; HANDLE hThread2 = NULL; int main(int argc, char *args[]) { hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //使用手動重置爲無信號狀態,初始化時無信號狀態 hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0,NULL); hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0,NULL); WaitForSingleObject( hThread1, INFINITE ); WaitForSingleObject( hThread2,INFINITE ); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程1被調用!\n"; } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程2被調用!\n"; } return 0; }
當建立手動重置事件時初始化爲無信號 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 獲得的結果是:
在hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 以後添加
SetEvent( hEvent );設置爲有信號,由於bManualReset爲TRUE時,等待該事件的全部線程均變爲可調度線程
當咱們在線程一中添加ResetEvent(hEvent);時運行程序發現線程1被調用,線程2沒有被調用:
三、
bManualReset:FALSE
bInitialState:TRUE
CreateEvent(NULL, FALSE, TRUE, NULL); //自動重置事件:當一個等待線程被釋放時,自動重置爲無信號狀態,初始是有信號狀態
#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI ThreadProc1(LPVOID lpParam); DWORD WINAPI ThreadProc2(LPVOID lpParam); HANDLE hEvent = NULL; HANDLE hThread1 = NULL; HANDLE hThread2 = NULL; int main(int argc, char *args[]) { hEvent = CreateEvent(NULL, FALSE, TRUE, NULL); //使用自動重置爲無信號狀態,初始化時有信號狀態 hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0,NULL); hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0,NULL); WaitForSingleObject( hThread1, INFINITE ); WaitForSingleObject( hThread2,INFINITE ); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程1被調用!\n"; } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程2被調用!\n"; } return 0; }
從結果能夠看到線程1被調用,線程2一直在等待。因爲CreateEvent(NULL, FALSE, TRUE, NULL)//使用自動重置爲無信號狀態,初始化時有信號狀態
因此當線程1執行的時候hEvent是有信號的,線程1正常運行,又因爲bManualReset爲FALSE時:當一個等待線程被釋放時,自動重置狀態爲無信號狀態
所以線程2一直在等待,因爲主線程加了WaitForSingleObject( hThread2,INFINITE ); 因此主線程也在一直等待
四、
bManualReset:FALSE
bInitialState:FALSE
CreateEvent(NULL, FALSE, FALSE, NULL);//自動重置事件:線程釋放後自動重置爲無信號狀態,初始化時爲無信號狀態
#include <iostream> #include <windows.h> using namespace std; DWORD WINAPI ThreadProc1(LPVOID lpParam); DWORD WINAPI ThreadProc2(LPVOID lpParam); HANDLE hEvent = NULL; HANDLE hThread1 = NULL; HANDLE hThread2 = NULL; int main(int argc, char *args[]) { hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //使用自動重置爲無信號狀態,初始化時無信號狀態 SetEvent(hEvent); hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0,NULL); hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0,NULL); WaitForSingleObject( hThread1, INFINITE ); WaitForSingleObject( hThread2,INFINITE ); return 0; } DWORD WINAPI ThreadProc1(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程1被調用!\n"; } return 0; } DWORD WINAPI ThreadProc2(LPVOID lpParam) { if ( WAIT_OBJECT_0 == WaitForSingleObject(hEvent,INFINITE) ) { cout <<"線程2被調用!\n"; } return 0; }
因爲CreateEvent(NULL, FALSE, FALSE, NULL);//使用手動重置爲無信號狀態,初始化時爲無信號狀態
因爲調用SetEvent,hEvent爲有信號狀態,線程1正常執行,又因爲bManualReset爲FALSE時: 當一個等待線程被釋放時,自動重置狀態爲無信號狀態,調用完線程1後,hEvent自動重置爲無信號狀態,因此線程2只能在等待