CEvent クラス
更新 : 2007 年 11 月
"イベント" を表します。これは、イベントが発生したことを、あるスレッドが別のスレッドに通知できるようにする同期オブジェクトです。
class CEvent : public CSyncObject
解説
イベントは、スレッドがいつその作業を行うかを知る必要があるときに有用です。たとえば、データをデータ アーカイブにコピーするスレッドは、新しいデータが利用できるようになったときに通知される必要があります。新しいデータが利用できるようになったとき、CEvent オブジェクトを使ってコピーを行うスレッドに通知をすると、スレッドはすぐにコピーを行うことができます。
CEvent オブジェクトには、手動と自動の 2 つの型があります。手動の CEvent オブジェクトは、他の関数が呼び出されるまで SetEvent または ResetEvent で設定された状態を維持します。自動の CEvent オブジェクトは、少なくとも 1 つのスレッドが解放された後に自動的に非シグナル状態 (利用できない状態) になります。
CEvent オブジェクトを使うには、必要になったときに CEvent オブジェクトを構築します。待機するイベント名を指定し、初めはアプリケーションがそのイベントを所有します。コンストラクタから戻るとイベントにアクセスできます。SetEvent を呼び出してイベント オブジェクトをシグナル状態 (利用できる状態) にします。その後、制御されるリソースへのアクセス終了時に Unlock を呼び出します。
CEvent オブジェクトのもう 1 つの使い方は、制御するクラスのデータ メンバとして、CEvent 型の変数を追加することです。制御されるオブジェクトの構築中に、CEvent データ メンバのコンストラクタを呼び出して、イベントを最初にシグナル状態にするかどうか、必要なイベント オブジェクトの型、イベント名 (プロセス間にまたがって使う場合)、および必要なセキュリティ属性を指定します。
この方法で CEvent オブジェクトが制御しているリソースにアクセスするには、まずリソースのアクセス メンバ関数に CSingleLock 型、または CMultiLock 型のどちらかの変数を作成します。その後、ロック オブジェクトの Lock メンバ関数 (たとえば、CMultiLock::Lock) を呼び出します。この時点でスレッドは、リソースにアクセスできるようになるか、リソースが解放されてアクセスできるようになるまで待つか、リソースが解放されるのを待ってタイムアウトとなってリソースへのアクセスができないかのいずれかの状態になります。いずれの場合も、リソースはスレッド セーフな方法でアクセスされています。リソースを解放するには SetEvent を呼び出してイベント オブジェクトをシグナル状態にし、その後ロック オブジェクトの Unlock メンバ関数 (たとえば、CMultiLock::Unlock) を呼び出すか、ロック オブジェクトがスコープ外になるようにします。
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 calulate 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
};
必要条件
ヘッダー : afxmt.h