天天看點

線程中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)

     {

         ………………

     }

在這個線程函數中可以可以通過設定mt_interval來控制這個線程的函數體多久執行一次,當事件為無信号狀态時函數體隔mt_interval執行一次,當設定事件為有信号狀态時,線程就執行完畢了(return 0)。

繼續閱讀