1. 程式人生 > >C++中event事件

C++中event事件

首先介紹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 WaitForSingleObject(

  HANDLE hHandle,

  DWORD dwMilliseconds

);

引數hHandle是一個事件的控制代碼,第二個引數dwMilliseconds是時間間隔。如果時間是有訊號狀態返回WAIT_OBJECT_0,如果時間超過dwMilliseconds值但時間事件還是無訊號狀態則返回WAIT_TIMEOUT。

hHandle可以是下列物件的控制代碼:

    Change notification

Console input

Event

Job

Memory resource notification

Mutex

Process

Semaphore

Thread

Waitable timer

WaitForSingleObject函式用來檢測hHandle事件的訊號狀態,當函式的執行時間超過dwMilliseconds就返回,但如果引數dwMilliseconds為INFINITE時函式將直到相應時間事件變成有訊號狀態才返回,否則就一直等待下去,直到WaitForSingleObject有返回直才執行後面的程式碼。在這裡舉個例子:

先建立一個全域性Event物件g_event:

    CEvent g_event;

在程式中可以通過呼叫CEvent::SetEvent設定事件為有訊號狀態。

下面是一個執行緒函式MyThreadPro()

UINT CFlushDlg::MyThreadProc( LPVOID pParam )

{

     WaitForSingleObject(g_event,INFINITE);

     For(;;)

        {

         ………….

        }

     return 0;

}

在這個執行緒函式中只有設定g_event為有訊號狀態時才執行下面的for迴圈,因為g_event是全域性變數,所以我們可以在別的執行緒中通過g_event. SetEvent控制這個執行緒。

還有一種用法就是我們可以通過WaitForSingleObject函式來間隔的執行一個執行緒函式的函式體

     UINT CFlushDlg::MyThreadProc( LPVOID pParam )

{

     while(WaitForSingleObject(g_event,MT_INTERVAL)!=WAIT_OBJECT_0)

     {

         ………………

     }

     return 0;

}

在這個執行緒函式中可以可以通過設定MT_INTERVAL來控制這個執行緒的函式體多久執行一次,當事件為無訊號狀態時函式體隔MT_INTERVAL執行一次,當設定事件為有訊號狀態時,執行緒就執行完畢了(return 0)。