天天看點

事件CEvent的使用 .

cevent類的一個對象,表示一個“事件”——一個允許一個事件發生時線程通知另一個線程的同步對象。在一個線程需要了解何時執行任務時,事件是十分有用的。例如,拷貝資料到資料文檔時,線程應被通知何時資料是可用的。當新資料可用時,通過運用cevent對象來通知拷貝線程,線程才可能盡快地執行。例如在某些網絡應用程式中,一個線程(記為a)負責監聽通信端口,另一個線程(記為b)負責更新使用者資料。通過使用cevent類,線程a可以通知線程b何時更新使用者資料,這樣線程b可以盡快地更新使用者資料。

cevent對象有兩種類型:自動和手工。一個手工cevent對象存在于由resetevent或setevent設定的狀态中,直到另一個函數被調用。一個自動cevent對象在至少一個線程被釋放後自動傳回一個無标記(無用的)狀态。

要使用一個cevent對象,應在需要時構造一個cevent對象。指定要等待的事件,應用應擁有它,就可以在構造函數傳回時通路事件。調用setevent标記(使可用)事件對象,然後當通路完控制資源時,調用unlock函數。

另一個使用cevent對象的方法是添加一個cevent類型的變量,使之成為希望控制的類的一個資料成員。在控制對象被構造期間,可調用cevent資料成員的構造函數,它指明時間是否是最初就被标記、需要的事件對象類型、事件名稱(如果在程序中要使用)和所希望的安全屬性。

cevent類的構造函數原型如下:

cevent( 

    bool binitiallyown /* = false */ ,    //用來指定事件對象初始狀态是否為發信狀态(預設值為未發信) 

    bool bmanualreset /* = false */ ,    //用來指定建立的事件對象是自動事件還是手動事件對象(預設值為自動事件對象) 

    lpctstr lpszname /* = null */ ,        //用來定義事件對象的名稱 

    lpsecurity_attributes lpsaattribute /* = null */         //指向一個lpsecurity_attributes結構的指針 

)

cevent類提供的三種方法

setevent()       //設定事件為發信狀态,并釋放其他正在等待的線程 

pulseevent()    //設定事件為發信狀态,并釋放其他正在等待的線程,然後把事件設定為未發信狀态 

resetevent()    //設定事件為未發信狀态

1.自動事件對象

如果使用cevent類構造函數的預設參數值的話,則定義的對象為自動事件對象。初始狀态為未發信狀态,可以用setevent使之變為發信狀态,等待線程中的第一個線程恢複運作,但事件對象會随即自動将其變為未發信狀态,進而使其他處于等待狀态的線程仍然被阻塞。就是說,自動事件對象一次隻能啟動一個處于等待狀态的線程。

示例:一個應用程式,當使用者在程式視窗上按下滑鼠左鍵時,會建立和啟動兩個線程,這兩個線程被啟動後,各自顯示一個資訊框,表明線程已被啟動,随即被事件對象的lock函數把線程挂起。當使用者在程式視窗按下滑鼠右鍵時,啟動另一個線程,在該線程中把事件對象置為“發信”狀态,進而啟動了第一個被挂起的線程。

1.建立單文檔程式;

2.在視圖類的實作檔案中定義一個全局事件對象:

cevent eventobj;

3.在視圖類的實作檔案編寫如下線程函數:

uint messagethread1(lpvoid pparam) 

    lptstr pmessage=_t("thread1 is started" ); 

    cwnd* pmainwnd=afxgetmainwnd(); 

    ::messagebox(pmainwnd->m_hwnd,pmessage,_t("thread message" ),mb_ok); 

    eventobj.lock();        //線程1處于等待狀态 

    /*-----------------------------------------------------------------*/  

    pmessage=_t("thread1 is unblocked" ); 

    ::messagebox(pmainwnd->m_hwnd,pmessage,_t("thread1 message" ),mb_ok);    //顯示線程1解鎖後的資訊框 

    eventobj.lock();        //線程1再次處于等待狀态 

    pmessage=_t("thread1 is unblocked again" ); 

    return  0 ; 

uint messagethread2(lpvoid pparam) 

    lptstr pmessage=_t("thread2 is started" ); 

    eventobj.lock();        //線程2處于等待狀态 

    pmessage=_t("thread2 is unblocked" ); 

    ::messagebox(pmainwnd->m_hwnd,pmessage,_t("thread2 message" ),mb_ok);    //顯示線程2解鎖後的資訊框 

uint messagethread3(lpvoid pparam) 

    eventobj.setevent();        //把事件對象置為發信狀态 

}

4.視圖類的滑鼠響應消息如下:

void  cthreadtestview::onlbuttondown(uint nflags, cpoint point) 

    afxbeginthread(messagethread1, _t("thread is started" )); //啟動線程1 

    afxbeginthread(messagethread2, _t("thread is started" )); //啟動線程2 

    cview::onlbuttondown(nflags, point); 

void  cthreadtestview::onrbuttondown(uint nflags, cpoint point) 

    afxbeginthread(messagethread3, _t("thread is unblocked" )); //啟動線程3 

    cview::onrbuttondown(nflags, point); 

程式運作結果:

事件CEvent的使用 .
事件CEvent的使用 .

2.手工事件對象

手工事件對象一旦用函數setevent設定為“發信”狀态,就一直處于有效狀态,除非又使用對象的成員函數pulseevent或resetevent把它重新設定為“未發信”狀态。是以手工事件對象被用來恢複多個處在等待狀态線程的運作。

示例:把上面的例子的事件對象定義為手工事件對象,然後運作該程式。

修改為下面代碼:

//把定義事件對象的代碼改為 

cevent eventobj(false,true);

事件CEvent的使用 .

繼續閱讀