Classe CEvent
Rappresenta un evento, ovvero un oggetto di sincronizzazione che consente a un thread di notificare a un altro che si è verificato un evento.
Sintassi
class CEvent : public CSyncObject
Membri
Costruttori pubblici
Nome | Descrizione |
---|---|
CEvent::CEvent |
Costruisce un oggetto CEvent . |
Metodi pubblici
Nome | Descrizione |
---|---|
CEvent::PulseEvent |
Imposta l'evento su disponibile (segnalato), rilascia thread in attesa e imposta l'evento su non disponibile (non firmato). |
CEvent::ResetEvent |
Imposta l'evento su non disponibile (non firmato). |
CEvent::SetEvent |
Imposta l'evento su disponibile (segnalato) e rilascia eventuali thread in attesa. |
CEvent::Unlock |
Rilascia l'oggetto evento. |
Osservazioni:
Gli eventi sono utili quando un thread deve sapere quando eseguire l'attività. Ad esempio, un thread che copia i dati in un archivio dati deve ricevere una notifica quando sono disponibili nuovi dati. Usando un CEvent
oggetto per notificare al thread di copia quando sono disponibili nuovi dati, il thread può eseguire l'attività il prima possibile.
CEvent
gli oggetti hanno due tipi: manuale e automatico.
Un oggetto automatico CEvent
torna automaticamente a uno stato non segnalato (non disponibile) dopo il rilascio di almeno un thread. Per impostazione predefinita, un CEvent
oggetto è automatico, a meno che non si passi TRUE
per il parametro durante la bManualReset
costruzione.
Un oggetto manuale CEvent
rimane nello stato impostato da SetEvent
o ResetEvent
fino a quando non viene chiamata l'altra funzione. Per creare un oggetto manuale CEvent
, passare TRUE
per il parametro durante la bManualReset
costruzione.
Per usare un CEvent
oggetto , costruire l'oggetto CEvent
quando necessario. Specificare il nome dell'evento che si vuole attendere e specificare anche che l'applicazione deve essere proprietaria inizialmente. È quindi possibile accedere all'evento quando viene restituito il costruttore. Chiamare SetEvent
per segnalare (rendere disponibile) l'oggetto evento e quindi chiamare Unlock
al termine dell'accesso alla risorsa controllata.
Un metodo alternativo per l'uso CEvent
degli oggetti consiste nell'aggiungere una variabile di tipo CEvent
come membro dati alla classe che si desidera controllare. Durante la costruzione dell'oggetto controllato, chiamare il costruttore del CEvent
membro dati e specificare se l'evento viene inizialmente segnalato e specificare anche il tipo di oggetto evento desiderato, il nome dell'evento (se verrà usato attraverso i limiti del processo) e gli attributi di sicurezza desiderati.
Per accedere a una risorsa controllata da un CEvent
oggetto in questo modo, creare prima di tutto una variabile di tipo o di tipo CSingleLock
CMultiLock
nel metodo di accesso della risorsa. Chiamare quindi il Lock
metodo dell'oggetto lock
, ad esempio CMultiLock::Lock
. A questo punto, il thread otterrà l'accesso alla risorsa, attenderà il rilascio della risorsa e otterrà l'accesso o attenderà il rilascio della risorsa, il timeout e non riuscirà ad accedere alla risorsa. In ogni caso, la risorsa è stata accessibile in modo thread-safe. Per rilasciare la risorsa, chiamare SetEvent
per segnalare l'oggetto evento e quindi usare il Unlock
metodo dell'oggetto ,ad esempio CMultiLock::Unlock
, oppure lasciare che l'oggetto non sia compreso nell'ambito lock
lock
.
Per altre informazioni su come usare CEvent
gli oggetti, vedere Multithreading: Come usare le classi di sincronizzazione.
Esempio
// 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
};
Gerarchia di ereditarietà
CEvent
Requisiti
Intestazione: afxmt.h
CEvent::CEvent
Costruisce un oggetto denominato o senza CEvent
nome.
CEvent(
BOOL bInitiallyOwn = FALSE,
BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
Parametri
bInitiallyOwn
Se TRUE
, il thread per l'oggetto CMultilock
o CSingleLock
è abilitato. In caso contrario, tutti i thread che desiderano accedere alla risorsa devono attendere.
bManualReset
Se TRUE
, specifica che l'oggetto evento è un evento manuale, in caso contrario l'oggetto evento è un evento automatico.
lpszName
Nome dell'oggetto CEvent
. Deve essere fornito se l'oggetto verrà usato oltre i limiti del processo. Se il nome corrisponde a un evento esistente, il costruttore compila un nuovo CEvent
oggetto che fa riferimento all'evento di tale nome. Se il nome corrisponde a un oggetto di sincronizzazione esistente che non è un evento, la costruzione avrà esito negativo. Se NULL
, il nome sarà Null.
lpsaAttribute
Attributi di sicurezza per l'oggetto evento. Per una descrizione completa di questa struttura, vedere SECURITY_ATTRIBUTES
in Windows SDK.
Osservazioni:
Per accedere o rilasciare un oggetto , creare un CEvent
CMultiLock
oggetto o CSingleLock
e chiamarne Lock
le funzioni membro e Unlock
.
Per modificare lo stato di un CEvent
oggetto in segnalato (i thread non devono attendere), chiamare SetEvent
o PulseEvent
. Per impostare lo stato di un CEvent
oggetto su non firmato (i thread devono attendere), chiamare ResetEvent
.
Importante
Dopo aver creato l'oggetto CEvent
, usare GetLastError
per assicurarsi che il mutex non esista già. Se il mutex esiste in modo imprevisto, potrebbe indicare che un processo non autorizzato è squatting e potrebbe voler usare il mutex in modo dannoso. In questo caso, la procedura consigliata per la sicurezza consiste nel chiudere l'handle e continuare come se si verificasse un errore nella creazione dell'oggetto.
CEvent::PulseEvent
Imposta lo stato dell'evento su segnalato (disponibile), rilascia tutti i thread in attesa e lo reimposta automaticamente su non firmato (non disponibile).
BOOL PulseEvent();
Valore restituito
Diverso da zero se la funzione ha avuto esito positivo; in caso contrario, 0.
Osservazioni:
Se l'evento è manuale, vengono rilasciati tutti i thread in attesa, l'evento viene impostato su non firmato e PulseEvent
restituisce . Se l'evento è automatico, viene rilasciato un singolo thread, l'evento viene impostato su non firmato e PulseEvent
restituisce .
Se nessun thread è in attesa o non è possibile rilasciare immediatamente thread, PulseEvent
imposta lo stato dell'evento su nonsignaled e restituisce.
PulseEvent
usa la funzione Win32 PulseEvent
sottostante, che può essere momentaneamente rimossa dallo stato di attesa da una chiamata di procedura asincrona in modalità kernel. Pertanto, PulseEvent
non è affidabile e non deve essere usato dalle nuove applicazioni. Per altre informazioni, vedere la PulseEvent
funzione .
CEvent::ResetEvent
Imposta lo stato dell'evento su non firmato fino a quando non viene impostato in modo esplicito su segnalato dalla SetEvent
funzione membro.
BOOL ResetEvent();
Valore restituito
Diverso da zero se la funzione ha avuto esito positivo; in caso contrario, 0.
Osservazioni:
In questo modo, tutti i thread che desiderano accedere a questo evento sono in attesa.
Questa funzione membro non viene usata dagli eventi automatici.
CEvent::SetEvent
Imposta lo stato dell'evento su segnalato, rilasciando eventuali thread in attesa.
BOOL SetEvent();
Valore restituito
Diverso da zero se la funzione ha avuto esito positivo; in caso contrario, 0.
Osservazioni:
Se l'evento è manuale, l'evento rimarrà segnalato fino a quando ResetEvent
non viene chiamato. In questo caso è possibile rilasciare più thread. Se l'evento è automatico, l'evento rimarrà segnalato fino al rilascio di un singolo thread. Il sistema imposta quindi lo stato dell'evento su non firmato. Se non sono in attesa thread, lo stato rimane segnalato fino a quando non viene rilasciato un thread.
CEvent::Unlock
Rilascia l'oggetto evento.
BOOL Unlock();
Valore restituito
Diverso da zero se il thread appartiene all'oggetto evento e l'evento è un evento automatico; in caso contrario, 0.
Osservazioni:
Questa funzione membro viene chiamata dai thread che attualmente possiedono un evento automatico per rilasciarlo al termine, se il relativo lock
oggetto deve essere riutilizzato. Se l'oggetto lock
non deve essere riutilizzato, questa funzione verrà chiamata dal lock
distruttore dell'oggetto.