分享方式:


CEvent 類別

表示事件,這是一個同步處理物件,可讓一個線程通知另一個事件已發生。

語法

class CEvent : public CSyncObject

成員

公用建構函式

名稱 描述
CEvent::CEvent 建構 CEvent 物件。

公用方法

名稱 描述
CEvent::PulseEvent 將事件設定為可用(已發出訊號)、釋放等候的線程,並將事件設定為無法使用(未簽署)。
CEvent::ResetEvent 將事件設定為無法使用(未簽署)。
CEvent::SetEvent 將事件設定為可用(已發出訊號),並釋放任何等候的線程。
CEvent::Unlock 釋放事件物件。

備註

當線程必須知道何時執行其工作時,事件會很有用。 例如,將數據複製到數據封存的線程必須在有新數據可用時收到通知。 藉由使用 CEvent 物件在有新數據可用時通知複製線程,線程可以儘快執行其工作。

CEvent 物件有兩種類型:手動和自動。

至少釋放一個線程之後,自動 CEvent 物件會自動回到非訊號(無法使用)狀態。 根據預設, CEvent 除非您在建構期間傳遞 TRUE 參數,否則對像是自動的 bManualReset

手動CEvent物件會留在 或 ResetEventSetEvent設定的狀態中,直到呼叫其他函式為止。 若要建立手動 CEvent 物件,請在建構期間傳遞 TRUE bManualReset 參數。

若要使用 CEvent 物件,請在需要時建構 CEvent 物件。 指定您想要等候的事件名稱,並指定應用程式應該一開始擁有它。 接著,您可以在建構函式傳回時存取 事件。 呼叫 SetEvent 以發出訊號(讓可用)事件物件,然後在您完成存取受控制資源時呼叫 Unlock

使用 CEvent 物件的替代方法是將 型 CEvent 別的變數新增為您想要控制之類別的數據成員。 在建構受控制物件期間,呼叫數據成員的 CEvent 建構函式,並指定事件是否一開始發出訊號,同時指定您想要的事件物件類型、事件的名稱(如果它會跨進程界限使用),以及您想要的任何安全性屬性。

若要以這種方式存取物件所 CEvent 控制的資源,請先在資源的存取方法中建立類型 CSingleLock 或類型的 CMultiLock 變數。 然後呼叫 Lock 物件的 方法 lock (例如 , CMultiLock::Lock。 此時,您的線程會取得資源的存取權、等候釋放資源並取得存取權,或等候資源釋放、逾時,以及無法取得資源的存取權。 在任何情況下,您的資源都已以安全線程的方式存取。 若要釋放資源,請呼叫 SetEvent 來發出事件對象的訊號,然後使用 Unlock 物件的方法 lock (例如 CMultiLock::Unlock),或讓 lock 對象脫離範圍。

如需如何使用 CEvent 對象的詳細資訊,請參閱 多線程:如何使用同步處理類別

範例

// The following demonstrates trivial usage of the CEvent class.
// A CEvent object is created and passed as a parameter to another
// thread.  The other thread will wait for the event to be signaled
// and then exit

UINT __cdecl MyThreadProc(LPVOID lpParameter)
{
   CEvent *pEvent = (CEvent *)(lpParameter);
   VERIFY(pEvent != NULL);

   // Wait for the event to be signaled
   ::WaitForSingleObject(pEvent->m_hObject, INFINITE);

   // Terminate the thread
   ::AfxEndThread(0, FALSE);
   return 0L;
}

void CEvent_Test()
{
   // Create the CEvent object that will be passed to the thread routine
   CEvent *pEvent = new CEvent(FALSE, FALSE);

   // Create a thread that will wait on the event
   CWinThread *pThread;
   pThread = ::AfxBeginThread(&MyThreadProc, pEvent, 0, 0, CREATE_SUSPENDED, NULL);
   pThread->m_bAutoDelete = FALSE;
   pThread->ResumeThread();

   // Signal the thread to do the next work item
   pEvent->SetEvent();

   // Wait for the thread to consume the event and return
   ::WaitForSingleObject(pThread->m_hThread, INFINITE);
   delete pThread;
   delete pEvent;
}

 

// This example builds upon the previous one.
// A second thread is created to calculate prime numbers.
// The main thread will signal the second thread to calculate the next
// prime number in the series.  The second thread signals the first
// after each number is calculated. Finally, after several iterations
// the worker thread is signaled to terminate.

class CPrimeTest
{
public:
   CPrimeTest()
       : m_pCalcNext(new CEvent(FALSE, FALSE)),
         m_pCalcFinished(new CEvent(FALSE, FALSE)),
         m_pTerminateThread(new CEvent(FALSE, FALSE)),
         m_iCurrentPrime(0)
   {
      // Create a thread that will calculate the prime numbers
      CWinThread *pThread;
      pThread = ::AfxBeginThread(&PrimeCalcProc,
                                 this, 0, 0, CREATE_SUSPENDED, NULL);
      pThread->m_bAutoDelete = FALSE;
      pThread->ResumeThread();

      // Calcuate the first 10 prime numbers in the series on the thread
      for (UINT i = 0; i < 10; i++)
      {
         // Signal the thread to do the next work item
         m_pCalcNext->SetEvent();
         // Wait for the thread to complete the current task
         ::WaitForSingleObject(m_pCalcFinished->m_hObject, INFINITE);
         // Print the result
         TRACE(_T("The value of m_iCurrentPrime is: %d\n"), m_iCurrentPrime);
      }

      // Notify the worker thread to exit and wait for it to complete
      m_pTerminateThread->SetEvent();
      ::WaitForSingleObject(pThread->m_hThread, INFINITE);
      delete pThread;
   }
   ~CPrimeTest()
   {
      delete m_pCalcNext;
      delete m_pCalcFinished;
      delete m_pTerminateThread;
   }

private:
   // Determines whether the given number is a prime number
   static BOOL IsPrime(INT ThisPrime)
   {
      if (ThisPrime < 2)
         return FALSE;

      for (INT n = 2; n < ThisPrime; n++)
      {
         if (ThisPrime % n == 0)
            return FALSE;
      }
      return TRUE;
   }

   // Calculates the next prime number in the series
   static INT NextPrime(INT ThisPrime)
   {
      while (TRUE)
      {
         if (IsPrime(++ThisPrime))
         {
            return ThisPrime;
         }
      }
   }

   // Worker thread responsible for calculating the next prime
   // number in the series
   static UINT __cdecl PrimeCalcProc(LPVOID lpParameter)
   {
      CPrimeTest *pThis = static_cast<CPrimeTest *>(lpParameter);
      VERIFY(pThis != NULL);

      VERIFY(pThis->m_pCalcNext != NULL);
      VERIFY(pThis->m_pCalcFinished != NULL);
      VERIFY(pThis->m_pTerminateThread != NULL);

      // Create a CMultiLock object to wait on the various events
      // WAIT_OBJECT_0 refers to the first event in the array,
      // WAIT_OBJECT_0+1 refers to the second
      CSyncObject *pWaitObjects[] = {pThis->m_pCalcNext,
                                     pThis->m_pTerminateThread};
      CMultiLock MultiLock(pWaitObjects, 2L);
      while (MultiLock.Lock(INFINITE, FALSE) == WAIT_OBJECT_0)
      {
         // Calculate next prime
         pThis->m_iCurrentPrime = NextPrime(pThis->m_iCurrentPrime);
         // Notify main thread calculation is complete
         pThis->m_pCalcFinished->SetEvent();
      }

      // Terminate the thread
      ::AfxEndThread(0, FALSE);
      return 0L;
   }

   CEvent *m_pCalcNext;        // notifies worker thread to calculate next prime
   CEvent *m_pCalcFinished;    // notifies main thread current calculation is complete
   CEvent *m_pTerminateThread; // notifies worker thread to terminate

   INT m_iCurrentPrime; // current calculated prime number
};

繼承階層架構

CObject

CSyncObject

CEvent

需求

標頭: afxmt.h

CEvent::CEvent

建構具名或未命名 CEvent 的物件。

CEvent(
    BOOL bInitiallyOwn = FALSE,
    BOOL bManualReset = FALSE,
    LPCTSTR lpszName = NULL,
    LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

參數

bInitiallyOwn
如果TRUE為 ,則會啟用 或 CSingleLock 對象的線程CMultilock。 否則,所有想要存取資源的線程都必須等候。

bManualReset
如果 TRUE為 ,則指定事件物件為手動事件,否則事件對象為自動事件。

lpszName
CEvent 物件的名稱。 如果物件將跨進程界限使用,則必須提供 。 如果名稱符合現有的事件,建構函式會建置參考該名稱事件的新 CEvent 物件。 如果名稱符合不是事件的現有同步處理物件,建構將會失敗。 如果 NULL為 ,則名稱會是 Null。

lpsaAttribute
事件對象的安全性屬性。 如需此結構的完整描述,請參閱 SECURITY_ATTRIBUTES Windows SDK。

備註

若要存取或釋放 CEvent 物件,請建立 CMultiLockCSingleLock 物件並呼叫其 LockUnlock 成員函式。

若要將物件的狀態 CEvent 變更為已發出訊號(線程不需要等候),請呼叫 SetEventPulseEvent。 若要將 物件的狀態 CEvent 設定為非對齊狀態(線程必須等候),請呼叫 ResetEvent

重要

建立 CEvent 對象之後,請使用 GetLastError 來確保 mutex 不存在。 如果 Mutex 確實出人意料地存在,則可能表示惡意程式正在蹲下,而且可能打算惡意使用 Mutex。 在此情況下,建議的安全性意識程式是關閉句柄並繼續,就像建立物件時發生失敗一樣。

CEvent::PulseEvent

將事件的狀態設定為已發出訊號(可用)、釋放任何等候的線程,並將它自動重設為非信號(無法使用)。

BOOL PulseEvent();

傳回值

如果函式成功,則為非零;否則為 0。

備註

如果事件是手動的,所有等候的線程都會釋放,事件會設定為非對齊,並 PulseEvent 傳回 。 勾選此事件為自動,則會釋放單一線程,事件會設定為非對齊,並 PulseEvent 傳回 。

如果沒有線程正在等候,或無法立即釋放線程, PulseEvent 請將事件的狀態設定為未簽署並傳回。

PulseEvent 會使用基礎 Win32 PulseEvent 函式,此函式可透過內核模式異步過程調用暫時從等候狀態中移除。 因此, PulseEvent 是不可靠的,不應該由新的應用程式使用。 如需詳細資訊,請參閱 PulseEvent 函式

CEvent::ResetEvent

將事件的狀態設定為非信號,直到明確設定為成員函式所發出訊號為止 SetEvent

BOOL ResetEvent();

傳回值

如果函式成功,則為非零;否則為 0。

備註

這會導致所有想要存取此事件的線程等候。

自動事件不會使用此成員函式。

CEvent::SetEvent

將事件的狀態設定為已發出訊號,釋放任何等候的線程。

BOOL SetEvent();

傳回值

如果函式成功,則為非零,否則為 0。

備註

如果事件是手動的,事件會保持訊號,直到呼叫為止 ResetEvent 。 在此情況下,可以釋放多個線程。 如果事件為自動,事件會保持訊號,直到釋放單一線程為止。 系統接著會將事件的狀態設定為非對齊狀態。 如果沒有線程正在等候,狀態會維持訊號,直到釋放一個線程為止。

CEvent::Unlock

釋放事件物件。

BOOL Unlock();

傳回值

如果線程擁有事件物件且事件是自動事件,則為非零;否則為 0。

備註

如果線程的對像是重複使用,則此成員函式是由目前擁有自動事件而擁有的線程所呼叫, lock 以便在完成之後釋放該函式。 lock如果物件不重複使用,物件解構函式將會呼叫lock此函式。

另請參閱

CSyncObject
階層架構圖表