Compartilhar via


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

CObject

CSyncObject

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.

Confira também

Classe CSyncObject
Gráfico da hierarquia