Compartir a través de


Clase CEvent

Representa un evento, que es un objeto de sincronización que permite que un subproceso notifique a otro que se ha producido un evento.

Sintaxis

class CEvent : public CSyncObject

Miembros

Constructores públicos

Nombre Descripción
CEvent::CEvent Construye un objeto CEvent.

Métodos públicos

Nombre Descripción
CEvent::PulseEvent Establece el evento en disponible (señalado), libera subprocesos en espera y establece el evento en no disponible (no señalado).
CEvent::ResetEvent Establece el evento en no disponible (no señalado).
CEvent::SetEvent Establece el evento en disponible (señalado) y libera los subprocesos en espera.
CEvent::Unlock Libera el objeto de evento.

Comentarios

Los eventos son útiles cuando un subproceso debe saber cuándo realizar su tarea. Por ejemplo, un subproceso que copia datos en un archivo de datos debe recibir una notificación cuando haya nuevos datos disponibles. Usando un objeto CEvent para notificar al subproceso de copia cuando haya nuevos datos disponibles, el subproceso puede realizar su tarea lo antes posible.

Los objetos CEvent tienen dos tipos: manual y automático.

Un objeto CEvent automático vuelve automáticamente a un estado no señalado (no disponible) después de liberar al menos un subproceso. De forma predeterminada, un objeto CEvent es automático a menos que pase TRUE para el parámetro bManualReset durante la construcción.

Un objeto CEvent manual permanece en el estado establecido por SetEvent o ResetEvent hasta que se llama a la otra función. Para crear un objeto manual CEvent, pase TRUE para el parámetro bManualReset durante la construcción.

Para usar un objeto CEvent, construya el objeto CEvent cuando sea necesario. Especifique el nombre del evento en el que quiere esperar y especifique también que la aplicación debe tenerlo inicialmente. A continuación, puede acceder al evento cuando el constructor devuelva resultados. Llame a SetEvent para indicar (poner a disposición) el objeto de evento y, luego, llame a Unlock cuando haya terminado de acceder al recurso controlado.

Un método alternativo para usar objetos CEvent es agregar una variable de tipo CEvent como miembro de datos a la clase que quiere controlar. Durante la construcción del objeto controlado, llame al constructor del miembro de datos CEvent y especifique si el evento está inicialmente señalado y también especifique el tipo de objeto de evento que quiera, el nombre del evento (si se va a usar entre los límites del proceso) y los atributos de seguridad que prefiera.

Para acceder a un recurso controlado por un objeto CEvent de esta manera, primero cree una variable de tipo CSingleLocko de tipo CMultiLock en el método de acceso del recurso. A continuación, llame al método Lock del objeto lock (por ejemplo, CMultiLock::Lock). En este momento, el subproceso obtendrá acceso al recurso, esperará a que el recurso se libere y obtenga acceso, o esperará a que el recurso se libere, se agote el tiempo de espera y no obtenga acceso al recurso. En cualquier caso, se ha accedido al recurso de forma segura para subproceso. Para liberar el recurso, llame a SetEvent para señalar el objeto de evento y, luego, use el método Unlock del objeto lock (por ejemplo, CMultiLock::Unlock) o deje que el objeto lock se quede fuera del ámbito.

Para más información sobre el uso de objetos CEvent, consulte el artículo Multithreading: Cómo usar las clases de sincronización.

Ejemplo

// 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
};

Jerarquía de herencia

CObject

CSyncObject

CEvent

Requisitos

Encabezado: afxmt.h

CEvent::CEvent

Construye un objeto CEvent con o sin nombre.

CEvent(
    BOOL bInitiallyOwn = FALSE,
    BOOL bManualReset = FALSE,
    LPCTSTR lpszName = NULL,
    LPSECURITY_ATTRIBUTES lpsaAttribute = NULL);

Parámetros

bInitiallyOwn
Si es TRUE, el subproceso del objeto CMultilock o CSingleLock está habilitado. De lo contrario, todos los subprocesos que quieran acceder al recurso deben esperar.

bManualReset
Si es TRUE, especifica que el objeto de evento es un evento manual; de lo contrario, el objeto de evento es un evento automático.

lpszName
Nombre del objeto CEvent. Debe proporcionarse si el objeto se usará entre los límites de proceso. Si el nombre coincide con un evento existente, el constructor crea un nuevo objeto CEvent que hace referencia al evento de ese nombre. Si el nombre coincide con un objeto de sincronización existente que no es un evento, se produce un error en la construcción. Si es NULL, el nombre será NULL.

lpsaAttribute
Atributos de seguridad del objeto de evento. Para ver una descripción completa de esta estructura, consulte SECURITY_ATTRIBUTES en Windows SDK.

Comentarios

Para obtener acceso a un objeto CEvent o liberarlo, cree un objeto CMultiLock o CSingleLock y llame a sus funciones miembro Lock y Unlock.

Para cambiar el estado de un objeto CEvent a señalado (los subprocesos no tienen que esperar), llame a SetEvent o PulseEvent. Para establecer el estado de un objeto CEvent en no señalado (los subprocesos deben esperar), llame a ResetEvent.

Importante

Después de crear el objeto CEvent, use GetLastError para asegurarse de que la exclusión mutua aún no existe. Si la exclusión mutua existía inesperadamente, puede indicar que un proceso no autorizado está en ocupación y puede estar intentando usar la exclusión mutua de forma malintencionada. En este caso, el procedimiento recomendado para la seguridad es cerrar el identificador y continuar como si hubiera un error al crear el objeto.

CEvent::PulseEvent

Establece el estado del evento en señalado (disponible), libera los subprocesos en espera y lo restablece automáticamente a no señalado (no disponible).

BOOL PulseEvent();

Valor devuelto

Distinto de cero si la función se realizó correctamente; de lo contrario, 0.

Comentarios

Si el evento es manual, se liberan todos los subprocesos en espera, el evento se establece en no señalado y PulseEvent devuelve resultados. Si el evento es automático, se libera un único subproceso, el evento se establece en no señalado y PulseEvent devuelve resultados.

Si no hay subprocesos en espera o no se puede liberar ningún subproceso inmediatamente, PulseEvent establece el estado del evento en no señalado y devuelve resultados.

PulseEvent usa la función PulseEvent subyacente de Win32, que se puede quitar momentáneamente del estado de espera mediante una llamada al procedimiento asincrónico en modo kernel. Por lo tanto, PulseEvent no es confiable y no se debe usar en las nuevas aplicaciones. Para obtener más información, vea Función PulseEvent.

CEvent::ResetEvent

Establece el estado del evento en no señalado hasta que la función miembro SetEvent lo establezca explícitamente en señalado.

BOOL ResetEvent();

Valor devuelto

Distinto de cero si la función se realizó correctamente; de lo contrario, 0.

Comentarios

Esto hace que todos los subprocesos que deseen acceder a este evento tengan que esperar.

Los eventos automáticos no usan esta función miembro.

CEvent::SetEvent

Establece el estado del evento en señalado, de forma que se liberan los subprocesos en espera.

BOOL SetEvent();

Valor devuelto

Es distinto de cero si la función se realizó correctamente; de lo contrario, es 0.

Comentarios

Si el evento es manual, permanecerá señalado hasta que se llame a ResetEvent. En este caso, se puede liberar más de un subproceso. Si el evento es automático, permanecerá señalado hasta que se libere un único subproceso. A continuación, el sistema establecerá el estado del evento en no señalado. Si no hay subprocesos en espera, el estado permanece señalado hasta que se libera un subproceso.

CEvent::Unlock

Libera el objeto de evento.

BOOL Unlock();

Valor devuelto

Distinto de cero si el subproceso pertenece al objeto de evento y el evento es un evento automático; de lo contrario, 0.

Comentarios

Esta función miembro la llaman los subprocesos que poseen actualmente un evento automático para liberarlo cuando hayan terminado, si se van a reutilizar sus objetos lock. Si el objeto lock no se va a reutilizar, el destructor del objeto lock llamará a esta función.

Consulte también

CSyncObject (clase)
Gráfico de jerarquías