事件CEvent的使用 .
CEvent類的一個對象,表示一個“事件”——一個允許一個事件發生時線程通知另一個線程的同步對象。在一個線程需要了解何時執行任務時,事件是十分有用的。例如,拷貝數據到數據文檔時,線程應被通知何時數據是可用的。當新數據可用時,通過運用CEvent對象來通知拷貝線程,線程才可能盡快地執行。例如在某些網絡應用程序中,一個線程(記為A)負責監聽通信端口,另一個線程(記為B)負責更新用戶數據。通過使用CEvent類,線程A可以通知線程B何時更新用戶數據,這樣線程B可以盡快地更新用戶數據。
CEvent對象有兩種類型:自動和手工。一個手工CEvent對象存在於由ResetEvent或SetEvent設置的狀態中,直到另一個函數被調用。一個自動CEvent對象在至少一個線程被釋放後自動返回一個無標記(無用的)狀態。
要使用一個CEvent對象,應在需要時構造一個CEvent對象。指定要等待的事件,應用應擁有它,就可以在構造函數返回時訪問事件。調用SetEvent標記(使可用)事件對象,然後當訪問完控製資源時,調用Unlock函數。
另一個使用CEvent對象的方法是添加一個CEvent類型的變量,使之成為希望控製的類的一個數據成員。在控製對象被構造期間,可調用CEvent數據成員的構造函數,它指明時間是否是最初就被標記、需要的事件對象類型、事件名稱(如果在進程中要使用)和所希望的安全屬性。
CEvent類的構造函數原型如下:
BOOL bInitiallyOwn /* = FALSE */ , //用來指定事件對象初始狀態是否為發信狀態(默認值為未發信)
BOOL bManualReset /* = FALSE */ , //用來指定創建的事件對象是自動事件還是手動事件對象(默認值為自動事件對象)
LPCTSTR lpszNAme /* = NULL */ , //用來定義事件對象的名稱
LPSECURITY_ATTRIBUTES lpsaAttribute /* = NULL */ //指向一個LPSECURITY_ATTRIBUTES結構的指針
)
CEvent類提供的三種方法
PulseEvent() //設置事件為發信狀態,並釋放其他正在等待的線程,然後把事件設置為未發信狀態
ResetEvent() //設置事件為未發信狀態
1.自動事件對象
如果使用CEvent類構造函數的默認參數值的話,則定義的對象為自動事件對象。初始狀態為未發信狀態,可以用SetEvent使之變為發信狀態,等待線程中的第一個線程恢複運行,但事件對象會隨即自動將其變為未發信狀態,從而使其他處於等待狀態的線程仍然被阻塞。就是說,自動事件對象一次隻能啟動一個處於等待狀態的線程。
示例:一個應用程序,當用戶在程序窗口上按下鼠標左鍵時,會創建和啟動兩個線程,這兩個線程被啟動後,各自顯示一個信息框,表明線程已被啟動,隨即被事件對象的Lock函數把線程掛起。當用戶在程序窗口按下鼠標右鍵時,啟動另一個線程,在該線程中把事件對象置為“發信”狀態,從而啟動了第一個被掛起的線程。
1.新建單文檔程序;
2.在視圖類的實現文件中定義一個全局事件對象:
3.在視圖類的實現文件編寫如下線程函數:
{
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" );
::MessageBox(pMainWnd->m_hWnd,pMessage,_T("Thread1 message" ),MB_OK); //顯示線程1解鎖後的信息框
return 0 ;
}
UINT MessageThread2(LPVOID pParam)
{
LPTSTR pMessage=_T("Thread2 is started" );
CWnd* pMainWnd=AfxGetMainWnd();
::MessageBox(pMainWnd->m_hWnd,pMessage,_T("Thread message" ),MB_OK);
eventObj.Lock(); //線程2處於等待狀態
/*-----------------------------------------------------------------*/
pMessage=_T("Thread2 is unblocked" );
::MessageBox(pMainWnd->m_hWnd,pMessage,_T("Thread2 message" ),MB_OK); //顯示線程2解鎖後的信息框
return 0 ;
}
UINT MessageThread3(LPVOID pParam)
{
eventObj.SetEvent(); //把事件對象置為發信狀態
return 0 ;
}
4.視圖類的鼠標響應消息如下:
{
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);
程序運行結果:
最後更新:2017-04-03 14:54:03