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);
程式運作結果:
2.手工事件對象
手工事件對象一旦用函數setevent設定為“發信”狀态,就一直處于有效狀态,除非又使用對象的成員函數pulseevent或resetevent把它重新設定為“未發信”狀态。是以手工事件對象被用來恢複多個處在等待狀态線程的運作。
示例:把上面的例子的事件對象定義為手工事件對象,然後運作該程式。
修改為下面代碼:
//把定義事件對象的代碼改為
cevent eventobj(false,true);