CEvent
-Klasse
Stellt ein Ereignis dar, bei dem es sich um ein Synchronisierungsobjekt handelt, das es einem Thread ermöglicht, einen anderen darüber zu benachrichtigen, dass ein Ereignis aufgetreten ist.
Syntax
class CEvent : public CSyncObject
Member
Öffentliche Konstruktoren
Name | Beschreibung |
---|---|
CEvent::CEvent |
Erstellt ein CEvent -Objekt. |
Öffentliche Methoden
Name | Beschreibung |
---|---|
CEvent::PulseEvent |
Legt das Ereignis auf verfügbar (signalisiert) fest, gibt Wartende Threads frei und legt das Ereignis auf nicht verfügbar (nicht signalisiert) fest. |
CEvent::ResetEvent |
Legt das Ereignis auf nicht verfügbar (nicht signaliert) fest. |
CEvent::SetEvent |
Legt das Ereignis auf verfügbar (signalisiert) fest und gibt alle wartenden Threads frei. |
CEvent::Unlock |
Gibt das Ereignisobjekt frei. |
Hinweise
Ereignisse sind nützlich, wenn ein Thread wissen muss, wann die Aufgabe ausgeführt werden soll. Beispielsweise muss ein Thread, der Daten in ein Datenarchiv kopiert, benachrichtigt werden, wenn neue Daten verfügbar sind. Durch Die Verwendung eines CEvent
Objekts, um den Kopierthread zu benachrichtigen, wenn neue Daten verfügbar sind, kann der Thread seine Aufgabe so schnell wie möglich ausführen.
CEvent
Objekte weisen zwei Typen auf: manuell und automatisch.
Ein automatisches CEvent
Objekt kehrt automatisch zu einem nicht signalisierten Zustand (nicht verfügbar) zurück, nachdem mindestens ein Thread losgelassen wurde. Standardmäßig wird ein CEvent
Objekt automatisch ausgeführt, es sei denn, Sie übergeben TRUE
den Parameter während der bManualReset
Konstruktion.
Ein manuelles CEvent
Objekt bleibt im Zustand, der von SetEvent
oder ResetEvent
bis zum Aufruf der anderen Funktion festgelegt ist. Übergeben Sie zum Erstellen eines manuellen CEvent
Objekts TRUE
den Parameter während der bManualReset
Konstruktion.
Um ein CEvent
Objekt zu verwenden, erstellen Sie das CEvent
Objekt, wenn es erforderlich ist. Geben Sie den Namen des Ereignisses an, das Sie warten möchten, und geben Sie außerdem an, dass die Anwendung sie ursprünglich besitzen soll. Sie können dann auf das Ereignis zugreifen, wenn der Konstruktor zurückgegeben wird. Rufen Sie SetEvent
das Ereignisobjekt auf (verfügbar machen), und rufen Sie dann auf Unlock
, wenn Sie mit dem Zugriff auf die kontrollierte Ressource fertig sind.
Eine alternative Methode zum Verwenden von CEvent
Objekten besteht darin, der Klasse, die Sie steuern möchten, eine Variable vom Typ CEvent
als Datenmememm hinzuzufügen. Rufen Sie beim Erstellen des gesteuerten Objekts den Konstruktor des CEvent
Datenelements auf, und geben Sie an, ob das Ereignis anfangs signalisiert wird, und geben Sie auch den gewünschten Ereignistyp, den Namen des Ereignisses (sofern es über Prozessgrenzen hinweg verwendet wird) und alle gewünschten Sicherheitsattribute an.
Um auf eine Ressource zuzugreifen, die auf diese Weise von einem CEvent
Objekt gesteuert wird, erstellen Sie zuerst eine Variable vom Typ CSingleLock
oder Typ CMultiLock
in der Zugriffsmethode Ihrer Ressource. Rufen Sie dann die Lock
Methode des lock
Objekts auf (z. B CMultiLock::Lock
. ). An diesem Punkt erhält Ihr Thread entweder Zugriff auf die Ressource, wartet auf die Freigabe der Ressource und erhält Zugriff, oder warten Sie, bis die Ressource freigegeben, timeout ist und keinen Zugriff auf die Ressource erhält. In jedem Fall wurde auf Ihre Ressource auf threadsichere Weise zugegriffen. Um die Ressource freizugeben, rufen Sie SetEvent
auf, um das Ereignisobjekt zu signalisieren, und verwenden Sie dann die Unlock
Methode des lock
Objekts (z. B CMultiLock::Unlock
. ), oder lassen Sie das lock
Objekt aus dem Bereich herausfallen.
Weitere Informationen zur Verwendung von CEvent
Objekten finden Sie unter Multithreading: Verwenden der Synchronisierungsklassen.
Beispiel
// 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
};
Vererbungshierarchie
CEvent
Anforderungen
Header: afxmt.h
CEvent::CEvent
Erstellt ein benanntes oder nicht benanntes CEvent
Objekt.
CEvent(
BOOL bInitiallyOwn = FALSE,
BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
Parameter
bInitiallyOwn
Wenn TRUE
der Thread für das CMultilock
Objekt CSingleLock
aktiviert ist. Andernfalls müssen alle Threads, die auf die Ressource zugreifen möchten, warten.
bManualReset
Wenn TRUE
, gibt an, dass das Ereignisobjekt ein manuelles Ereignis ist, andernfalls ist das Ereignisobjekt ein automatisches Ereignis.
lpszName
Name des CEvent
-Objekts. Muss angegeben werden, wenn das Objekt über Prozessgrenzen hinweg verwendet wird. Wenn der Name einem vorhandenen Ereignis entspricht, erstellt der Konstruktor ein neues CEvent
Objekt, das auf das Ereignis dieses Namens verweist. Wenn der Name einem vorhandenen Synchronisierungsobjekt entspricht, das kein Ereignis ist, schlägt die Konstruktion fehl. If NULL
, the name will be null.
lpsaAttribute
Sicherheitsattribute für das Ereignisobjekt. Eine vollständige Beschreibung dieser Struktur finden Sie im SECURITY_ATTRIBUTES
Windows SDK.
Hinweise
Um auf ein CEvent
Objekt zuzugreifen oder freizugeben, erstellen Sie ein CMultiLock
Objekt oder CSingleLock
ein Objekt, und rufen Sie dessen Lock
Funktionen und Unlock
Memberfunktionen auf.
Um den Status eines CEvent
Objekts zu ändern, das signalisiert wird (Threads müssen nicht warten), aufrufen SetEvent
oder PulseEvent
. Rufen Sie auf, um den Status eines CEvent
Objekts auf "nichtsignaliert" festzulegen (Threads müssen warten).ResetEvent
Wichtig
Verwenden Sie GetLastError
nach dem Erstellen des CEvent
Objekts, um sicherzustellen, dass das Mutex noch nicht vorhanden war. Wenn der Mutex unerwartet vorhanden ist, kann es darauf hindeuten, dass ein nicht autorisierter Prozess gleicht und möglicherweise beabsichtigt, den Mutex böswillig zu verwenden. In diesem Fall besteht die empfohlene sicherheitsbewusste Prozedur darin, das Handle zu schließen und fortzusetzen, als ob beim Erstellen des Objekts ein Fehler aufgetreten wäre.
CEvent::PulseEvent
Legt den Status des Ereignisses auf signalisiert (verfügbar) fest, gibt alle Wartethreads frei und setzt ihn automatisch auf nicht signalisiert (nicht verfügbar) zurück.
BOOL PulseEvent();
Rückgabewert
Nonzero, wenn die Funktion erfolgreich war; andernfalls 0.
Hinweise
Wenn das Ereignis manuell ist, werden alle wartenden Threads freigegeben, das Ereignis wird auf nicht signaliert festgelegt und PulseEvent
zurückgegeben. Wenn das Ereignis automatisch ausgeführt wird, wird ein einzelner Thread losgelassen, das Ereignis wird auf "nicht signaliert" festgelegt und PulseEvent
zurückgegeben.
Wenn keine Threads warten oder keine Threads sofort freigegeben werden können, PulseEvent
wird der Status des Ereignisses auf nicht signallos festgelegt und zurückgegeben.
PulseEvent
verwendet die zugrunde liegende Win32-Funktion PulseEvent
, die von einem asynchronen Prozeduraufruf im Kernelmodus aus dem Wartezustand entfernt werden kann. PulseEvent
Daher ist unzuverlässig und sollte nicht von neuen Anwendungen verwendet werden. Weitere Informationen finden Sie unter PulseEvent
-Funktion.
CEvent::ResetEvent
Legt den Zustand des Ereignisses auf "nicht signalisiert" fest, bis es explizit auf das Signal der SetEvent
Memberfunktion festgelegt ist.
BOOL ResetEvent();
Rückgabewert
Nonzero, wenn die Funktion erfolgreich war; andernfalls 0.
Hinweise
Dies bewirkt, dass alle Threads, die auf dieses Ereignis zugreifen möchten, warten.
Diese Memberfunktion wird nicht von automatischen Ereignissen verwendet.
CEvent::SetEvent
Legt den Status des Ereignisses fest, das signalisiert wird, und gibt alle wartenden Threads frei.
BOOL SetEvent();
Rückgabewert
Nonzero, wenn die Funktion erfolgreich war, andernfalls 0.
Hinweise
Wenn das Ereignis manuell ist, bleibt das Ereignis bis zum ResetEvent
Aufrufen signalisiert. In diesem Fall können mehrere Threads freigegeben werden. Wenn das Ereignis automatisch erfolgt, wird das Ereignis bis zur Veröffentlichung eines einzelnen Threads signalisiert. Das System legt dann den Status des Ereignisses auf "Nichtsignal" fest. Wenn keine Threads warten, bleibt der Zustand bis zur Veröffentlichung eines Threads signalisiert.
CEvent::Unlock
Gibt das Ereignisobjekt frei.
BOOL Unlock();
Rückgabewert
Nonzero, wenn der Thread dem Ereignisobjekt gehört und das Ereignis ein automatisches Ereignis ist; andernfalls 0.
Hinweise
Diese Memberfunktion wird von Threads aufgerufen, die derzeit über ein automatisches Ereignis verfügen, um es nach abschluss des Vorgangs freizugeben, wenn ihr lock
Objekt wiederverwendet werden soll. Wenn das lock
Objekt nicht wiederverwendet werden soll, wird diese Funktion vom Destruktor des lock
Objekts aufgerufen.