次の方法で共有


CEvent クラス

イベントを表します。これは、あるスレッドがイベントが発生したことを別のスレッドに通知できるようにする同期オブジェクトです。

構文

class CEvent : public CSyncObject

メンバー

パブリック コンストラクター

名前 説明
CEvent::CEvent CEvent オブジェクトを構築します。

パブリック メソッド

名前 説明
CEvent::PulseEvent イベントを使用可能 (シグナル) に設定し、待機中のスレッドを解放し、イベントを使用不可 (非割り当て) に設定します。
CEvent::ResetEvent イベントを使用不可 (非署名) に設定します。
CEvent::SetEvent イベントを使用可能 (シグナル) に設定し、待機しているスレッドを解放します。
CEvent::Unlock イベント オブジェクトを解放します。

解説

イベントは、スレッドがそのタスクを実行するタイミングを知る必要がある場合に便利です。 たとえば、データアーカイブにデータをコピーするスレッドは、新しいデータが使用可能になったときに通知を受け取る必要があります。 CEvent オブジェクトを使用して、新しいデータが使用可能になったときにコピー スレッドに通知することで、スレッドはできるだけ早くタスクを実行できます。

CEvent オブジェクトには、手動と自動の 2 種類があります。

自動 CEvent オブジェクトは、少なくとも 1 つのスレッドが解放された後、非シグナル状態 (使用不可) に自動的に戻ります。 既定では、CEvent オブジェクトは、構築時に bManualReset パラメーターのTRUEを渡さない限り、自動です。

手動 CEvent オブジェクトは、他の関数が呼び出されるまで、 SetEvent または ResetEvent によって設定された状態のままです。 手動CEvent オブジェクトを作成するには、構築時に bManualReset パラメーターのTRUEを渡します。

CEvent オブジェクトを使用するには、必要に応じてCEvent オブジェクトを構築します。 待機するイベントの名前を指定し、アプリケーションが最初にイベントを所有するように指定します。 その後、コンストラクターが戻ったときにイベントにアクセスできます。 SetEventを呼び出してイベント オブジェクトに通知 (使用可能にする) し、制御されたリソースへのアクセスが完了したらUnlockを呼び出します。

CEventオブジェクトを使用する別の方法は、CEvent型の変数を、制御するクラスのデータ メンバーとして追加することです。 制御されたオブジェクトの構築中に、 CEvent データ メンバーのコンストラクターを呼び出し、イベントが最初に通知されるかどうかを指定し、必要なイベント オブジェクトの種類、イベントの名前 (プロセス境界を越えて使用される場合)、必要なセキュリティ属性も指定します。

この方法で CEvent オブジェクトによって制御されるリソースにアクセスするには、まず、リソースのアクセス方法に CSingleLock 型または CMultiLock 型のいずれかの変数を作成します。 次に、lock オブジェクトのLock メソッド (たとえば、CMultiLock::Lock) を呼び出します。 この時点で、スレッドはリソースへのアクセス権を取得するか、リソースが解放されてアクセスを得るのを待つか、リソースが解放されるのを待ってタイムアウトし、リソースへのアクセスに失敗します。 いずれの場合も、リソースにはスレッド セーフな方法でアクセスされています。 リソースを解放するには、SetEventを呼び出してイベント オブジェクトを通知し、lock オブジェクトの Unlock メソッド (CMultiLock::Unlock など) を使用するか、lock オブジェクトをスコープ外にします。

CEvent オブジェクトの使用方法の詳細については、「Multithreading: How to Use the Synchronization Classes」を参照してください。

// 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場合、CMultilockまたはCSingleLock オブジェクトのスレッドが有効になります。 それ以外の場合、リソースにアクセスするすべてのスレッドは待機する必要があります。

bManualReset
TRUE場合は、イベント オブジェクトが手動イベントであることを指定します。それ以外の場合、イベント オブジェクトは自動イベントです。

lpszName
CEvent オブジェクトの名前。 オブジェクトがプロセス境界を越えて使用される場合は、指定する必要があります。 名前が既存のイベントと一致する場合、コンストラクターは、その名前のイベントを参照する新しい CEvent オブジェクトをビルドします。 名前がイベントではない既存の同期オブジェクトと一致する場合、構築は失敗します。 NULL場合、名前は null になります。

lpsaAttribute
イベント オブジェクトのセキュリティ属性。 この構造の詳細については、Windows SDK の SECURITY_ATTRIBUTES を参照してください。

解説

CEvent オブジェクトにアクセスまたは解放するには、CMultiLockまたはCSingleLock オブジェクトを作成し、そのLockおよびメンバー関数Unlock呼び出します。

CEvent オブジェクトの状態をシグナル通知に変更するには (スレッドを待機する必要はありません)、SetEventまたはPulseEventを呼び出します。 CEvent オブジェクトの状態を非署名 (スレッドは待機する必要があります) に設定するには、ResetEventを呼び出します。

重要

CEvent オブジェクトを作成した後、GetLastErrorを使用してミューテックスがまだ存在していないことを確認します。 ミューテックスが予期せず存在していた場合は、不正なプロセスがしゃがみ込み、ミューテックスを悪意を持って使用しようとしている可能性があることを示している可能性があります。 この場合、推奨されるセキュリティ意識の高い手順は、ハンドルを閉じて、オブジェクトの作成に失敗したかのように続行することです。

CEvent::PulseEvent

イベントの状態をシグナル通知 (使用可能) に設定し、待機中のスレッドをすべて解放し、自動的に非署名 (使用不可) にリセットします。

BOOL PulseEvent();

戻り値

関数が成功した場合は 0 以外。それ以外の場合は 0。

解説

イベントが手動の場合、待機しているすべてのスレッドが解放され、イベントが非署名に設定され、 PulseEvent が返されます。 イベントが自動で、1 つのスレッドが解放され、イベントが非署名に設定され、 PulseEvent が返されます。

待機しているスレッドがない場合、またはスレッドをすぐに解放できない場合は、イベントの状態を非署名に設定 PulseEvent 戻ります。

PulseEvent は、基になる Win32 PulseEvent 関数を使用します。これは、カーネル モードの非同期プロシージャ呼び出しによって待機状態から一時的に削除される可能性があります。 そのため、 PulseEvent は信頼性が低く、新しいアプリケーションでは使用しないでください。 詳細については、PulseEvent 関数に関するページを参照してください。

CEvent::ResetEvent

SetEvent メンバー関数によって明示的にシグナル通知に設定されるまで、イベントの状態を非署名に設定します。

BOOL ResetEvent();

戻り値

関数が成功した場合は 0 以外。それ以外の場合は 0。

解説

これにより、このイベントにアクセスするすべてのスレッドが待機します。

このメンバー関数は、自動イベントでは使用されません。

CEvent::SetEvent

イベントの状態をシグナル通知に設定し、待機中のスレッドを解放します。

BOOL SetEvent();

戻り値

関数が成功した場合は 0 以外、それ以外の場合は 0。

解説

イベントが手動の場合、イベントは ResetEvent が呼び出されるまで通知されたままになります。 この場合、複数のスレッドを解放できます。 イベントが自動の場合、1 つのスレッドが解放されるまで、イベントは通知されたままになります。 その後、システムはイベントの状態を非署名に設定します。 待機しているスレッドがない場合、1 つのスレッドが解放されるまで状態はシグナル状態のままになります。

CEvent::Unlock

イベント オブジェクトを解放します。

BOOL Unlock();

戻り値

スレッドがイベント オブジェクトを所有していて、イベントが自動イベントの場合は 0 以外。それ以外の場合は 0。

解説

このメンバー関数は、現在、自動イベントを所有しているスレッドによって呼び出され、その lock オブジェクトが再利用される場合、そのイベントが完了した後に解放されます。 lock オブジェクトを再利用しない場合、この関数はlock オブジェクトのデストラクターによって呼び出されます。

関連項目

CSyncObject クラス
階層図