Classe CEvent
Representa um evento, que é um objeto de sincronização que permite que um thread notifique outro de que ocorreu um evento.
Sintaxe
class CEvent : public CSyncObject
Membros
Construtores públicos
Nome | Descrição |
---|---|
CEvent::CEvent |
Constrói um objeto CEvent . |
Métodos públicos
Nome | Descrição |
---|---|
CEvent::PulseEvent |
Define o evento como disponível (sinalizado), libera threads de espera e define o evento como indisponível (não sinalizado). |
CEvent::ResetEvent |
Define o evento como indisponível (não sinalizado). |
CEvent::SetEvent |
Define o evento como disponível (sinalizado) e libera todos os threads de espera. |
CEvent::Unlock |
Libera o objeto de evento. |
Comentários
Os eventos são úteis quando um thread precisa saber quando executar sua tarefa. Por exemplo, um thread que copia dados para um arquivo de dados deve ser notificado quando novos dados estiverem disponíveis. Usando um objeto CEvent
para notificar o thread de cópia quando novos dados estiverem disponíveis, o thread poderá executar sua tarefa o mais rápido possível.
Os objetos CEvent
têm dois tipos: manual e automático.
Um objeto CEvent
automático retorna automaticamente a um estado não sinalizado (indisponível) depois que pelo menos um thread é liberado. Por padrão, um objeto CEvent
é automático, a menos que você passe TRUE
para o parâmetro bManualReset
durante a construção.
Um objeto CEvent
manual permanece no estado definido por SetEvent
ou ResetEvent
até que a outra função seja chamada. Para criar um objeto CEvent
manual, passe TRUE
para o parâmetro bManualReset
durante a construção.
Para usar um objeto CEvent
, construa o objeto CEvent
quando for necessário. Especifique o nome do evento em que você deseja aguardar e especifique que seu aplicativo deve inicialmente possuí-lo. Em seguida, você pode acessar o evento quando o construtor retornar. Chame SetEvent
para sinalizar (tornar disponível) o objeto de evento e, em seguida, chame Unlock
quando terminar de acessar o recurso controlado.
Um método alternativo para usar objetos CEvent
é adicionar uma variável de tipo CEvent
como um membro de dados à classe que você quer controlar. Durante a construção do objeto controlado, chame o construtor do membro de dados CEvent
e especifique se o evento é inicialmente sinalizado e também especifique o tipo de objeto de evento desejado, o nome do evento (se ele será usado entre os limites do processo) e quaisquer atributos de segurança desejados.
Para acessar um recurso controlado por um objeto CEvent
dessa maneira, primeiro crie uma variável de tipo CSingleLock
ou CMultiLock
no mecanismo de acesso do recurso. Em seguida, chame o método Lock
do objeto lock
(por exemplo, CMultiLock::Lock
). Neste ponto, ou o thread terá acesso ao recurso, ou aguardará a liberação do recurso e obterá acesso, ou aguardará o recurso ser liberado e atingir tempo limite, não obtendo acesso ao recurso. De qualquer forma, seu recurso foi acessado de maneira thread-safe. Para liberar o recurso, chame SetEvent
para sinalizar o objeto de evento e, em seguida, use o método Unlock
do objeto lock
(por exemplo, CMultiLock::Unlock
) ou deixe o objeto lock
sair do escopo.
Para obter mais informações sobre como usar objetos CEvent
, consulte Multithreading: como usar as classes de sincronização.
Exemplo
// 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
};
Hierarquia de herança
CEvent
Requisitos
Cabeçalho: afxmt.h
CEvent::CEvent
Constrói um objeto CEvent
nomeado ou sem nome.
CEvent(
BOOL bInitiallyOwn = FALSE,
BOOL bManualReset = FALSE,
LPCTSTR lpszName = NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);
Parâmetros
bInitiallyOwn
Se TRUE
, o thread para o objeto CMultilock
ou CSingleLock
está habilitado. Caso contrário, todos os threads que desejam acessar o recurso deverão aguardar.
bManualReset
Se TRUE
, especifica que o objeto de evento é um evento manual, caso contrário, o objeto de evento é um evento automático.
lpszName
Nome do objeto de CEvent
. Deve ser fornecido se o objeto for usado entre os limites do processo. Se o nome corresponder a um evento existente, o construtor criará um novo objeto CEvent
que referencia o evento desse nome. Se o nome corresponder a um objeto de sincronização existente que não seja um evento, a construção falhará. Se NULL
, o nome será nulo.
lpsaAttribute
Atributos de segurança para o objeto de evento. Para obter uma descrição completa dessa estrutura, consulte SECURITY_ATTRIBUTES
no SDK do Windows.
Comentários
Para acessar ou liberar um objeto CEvent
, crie um objeto CMultiLock
ou CSingleLock
e chame suas funções membro Lock
e Unlock
.
Para alterar o estado de um objeto CEvent
para sinalizado (threads não precisam esperar), chame SetEvent
ou PulseEvent
. Para definir o estado de um objeto CEvent
como não sinalizado (os threads devem esperar), chame ResetEvent
.
Importante
Depois de criar o objeto CEvent
, use GetLastError
para garantir que o mutex ainda não exista. Se o mutex existiu inesperadamente, isso pode indicar que um processo desonesto está em squatting e pode estar pretendendo usar o mutex maliciosamente. Nesse caso, o procedimento recomendado consciente da segurança é fechar o identificador e continuar como se houvesse uma falha na criação do objeto.
CEvent::PulseEvent
Define o estado do evento como sinalizado (disponível), libera todos os threads de espera e o redefine para não sinalizado (indisponível) automaticamente.
BOOL PulseEvent();
Valor de retorno
Diferente de zero se a função foi bem-sucedida, caso contrário, 0.
Comentários
Se o evento for manual, todos os threads de espera serão liberados, o evento será definido como não sinalizado e PulseEvent
retornará. Se o evento for automático, um único thread será liberado, o evento será definido como não sinalizado e PulseEvent
retornará.
Se nenhum thread estiver esperando ou nenhum thread puder ser liberado imediatamente, PulseEvent
definirá o estado do evento como não sinalizado e retornará.
PulseEvent
usa a função PulseEvent
do Win32 subjacente, que pode ser removida momentaneamente do estado de espera por uma chamada de procedimento assíncrono no modo kernel. Portanto, PulseEvent
não é confiável e não deve ser usado por novos aplicativos. Para saber mais consulte PulseEvent
função.
CEvent::ResetEvent
Define o estado do evento como não sinalizado até que seja explicitamente definido como sinalizado pela função membro SetEvent
.
BOOL ResetEvent();
Valor de retorno
Diferente de zero se a função foi bem-sucedida, caso contrário, 0.
Comentários
Isso faz com que todos os threads que desejam acessar esse evento aguardem.
Essa função membro não é usada por eventos automáticos.
CEvent::SetEvent
Define o estado do evento como sinalizado liberando quaisquer threads em espera.
BOOL SetEvent();
Valor de retorno
Diferente de zero se a função foi bem-sucedida; caso contrário, zero.
Comentários
Se o evento for manual, ele permanecerá sinalizado até ResetEvent
ser chamado. Nesse caso, mais de um thread pode ser liberado. Se o evento for automático, ele permanecerá sinalizado até que um único thread seja liberado. Em seguida, o sistema definirá o estado do evento como não sinalizado. Se nenhum thread estiver esperando, o estado permanecerá sinalizado até que um thread seja liberado.
CEvent::Unlock
Libera o objeto de evento.
BOOL Unlock();
Valor de retorno
Diferente de zero se o thread possuía o objeto de evento e o evento é automático; caso contrário, zero.
Comentários
Essa função membro é chamada por threads que atualmente possuem um evento automático para liberá-lo depois de concluído, se seu objeto lock
for reutilizado. Se o objeto lock
não for reutilizado, essa função será chamada pelo destruidor do objeto lock
.