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


事件CEvent的使用 .

CEvent類的一個對象,表示一個“事件”——一個允許一個事件發生時線程通知另一個線程的同步對象。在一個線程需要了解何時執行任務時,事件是十分有用的。例如,拷貝數據到數據文檔時,線程應被通知何時數據是可用的。當新數據可用時,通過運用CEvent對象來通知拷貝線程,線程才可能盡快地執行。例如在某些網絡應用程序中,一個線程(記為A)負責監聽通信端口,另一個線程(記為B)負責更新用戶數據。通過使用CEvent類,線程A可以通知線程B何時更新用戶數據,這樣線程B可以盡快地更新用戶數據。
CEvent對象有兩種類型:自動和手工。一個手工CEvent對象存在於由ResetEventSetEvent設置的狀態中,直到另一個函數被調用。一個自動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" ); 
    ::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.視圖類的鼠標響應消息如下:

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設置為“發信”狀態,就一直處於有效狀態,除非又使用對象的成員函數PulseEventResetEvent把它重新設置為“未發信”狀態。所以手工事件對象被用來恢複多個處在等待狀態線程的運行。

示例:把上麵的例子的事件對象定義為手工事件對象,然後運行該程序。
修改為下麵代碼:

//把定義事件對象的代碼改為 
CEvent eventObj(FALSE,TRUE);

程序運行結果:

最後更新:2017-04-03 14:54:03

  上一篇:go 精通css(1)-規範
  下一篇:go poj 1484 Blowing Fuses