CEvent
類別
表示事件,這是一個同步處理物件,可讓一個線程通知另一個事件已發生。
語法
class CEvent : public CSyncObject
成員
公用建構函式
名稱 | 描述 |
---|---|
CEvent::CEvent |
建構 CEvent 物件。 |
公用方法
名稱 | 描述 |
---|---|
CEvent::PulseEvent |
將事件設定為可用(已發出訊號)、釋放等候的線程,並將事件設定為無法使用(未簽署)。 |
CEvent::ResetEvent |
將事件設定為無法使用(未簽署)。 |
CEvent::SetEvent |
將事件設定為可用(已發出訊號),並釋放任何等候的線程。 |
CEvent::Unlock |
釋放事件物件。 |
備註
當線程必須知道何時執行其工作時,事件會很有用。 例如,將數據複製到數據封存的線程必須在有新數據可用時收到通知。 藉由使用 CEvent
物件在有新數據可用時通知複製線程,線程可以儘快執行其工作。
CEvent
物件有兩種類型:手動和自動。
至少釋放一個線程之後,自動 CEvent
物件會自動回到非訊號(無法使用)狀態。 根據預設, CEvent
除非您在建構期間傳遞 TRUE
參數,否則對像是自動的 bManualReset
。
手動CEvent
物件會留在 或 ResetEvent
所SetEvent
設定的狀態中,直到呼叫其他函式為止。 若要建立手動 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
};
繼承階層架構
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
物件,請建立 CMultiLock
或 CSingleLock
物件並呼叫其 Lock
和 Unlock
成員函式。
若要將物件的狀態 CEvent
變更為已發出訊號(線程不需要等候),請呼叫 SetEvent
或 PulseEvent
。 若要將 物件的狀態 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
此函式。