閱讀658 返回首頁    go 阿裏雲 go 技術社區[雲棲]


線程中CreateEvent和SetEvent及WaitForSingleObject的用法

首先介紹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)。

最後更新:2017-04-03 14:53:38

  上一篇:go 【轉載】人到中年須具備的心情修養
  下一篇:go win32程序中簡單應用mfc