window下線程同步之(Event Objects(事件))

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

 

bManualResetTRUE時:  人工重置事件,當一個等待線程被釋放時,必須使用ResetEvent()手動重置爲無型號狀態安全

                                        當人工重置的事件獲得通知時,等待該事件的全部線程均變爲可調度線程。app

 

bManualResetFALSE時: 自動重置事件,當一個等待線程被釋放時,自動重置狀態爲無信號狀態
                                     當自動重置的事件獲得通知時,等待該事件的線程中只有一個線程變爲可調度線程。函數

自動重置事件(一般沒有必要爲自動重置的事件調用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); 獲得的結果是:

image

在hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 以後添加

SetEvent( hEvent );設置爲有信號,由於bManualReset爲TRUE時,等待該事件的全部線程均變爲可調度線程

image

當咱們在線程一中添加ResetEvent(hEvent);時運行程序發現線程1被調用,線程2沒有被調用:

image

 

三、
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; 
} 

image

從結果能夠看到線程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; 
} 

image

因爲CreateEvent(NULL, FALSE, FALSE, NULL);//使用手動重置爲無信號狀態,初始化時爲無信號狀態

因爲調用SetEvent,hEvent爲有信號狀態,線程1正常執行,又因爲bManualReset爲FALSE時: 當一個等待線程被釋放時,自動重置狀態爲無信號狀態,調用完線程1後,hEvent自動重置爲無信號狀態,因此線程2只能在等待

相關文章
相關標籤/搜索