Поделиться через


Класс CEvent

Представляет событие, которое является объектом синхронизации, который позволяет одному потоку уведомлять другого о том, что произошло событие.

Синтаксис

class CEvent : public CSyncObject

Участники

Открытые конструкторы

Имя Описание
CEvent::CEvent Формирует объект CEvent.

Открытые методы

Имя Описание
CEvent::PulseEvent Задает событие доступным (сигналом), освобождает потоки ожидания и задает событие недоступным (незначимым).
CEvent::ResetEvent Задает для события недоступность (незначаемое).
CEvent::SetEvent Задает событие доступным (сигналом) и освобождает все потоки ожидания.
CEvent::Unlock Освобождает объект события.

Замечания

События полезны, когда поток должен знать, когда выполняется задача. Например, поток, копирующий данные в архив данных, должен быть уведомлен при наличии новых данных. Используя CEvent объект для уведомления потока копирования о доступности новых данных, поток может выполнять свою задачу как можно скорее.

CEvent Объекты имеют два типа: вручную и автоматически.

Автоматический CEvent объект автоматически возвращается в состояние без сигнала (недоступно) после освобождения по крайней мере одного потока. По умолчанию объект является автоматическим, CEvent если вы не передаете TRUE параметр bManualReset во время построения.

Объект вручную CEvent остается в состоянии, заданном SetEvent или ResetEvent пока не будет вызвана другая функция. Чтобы создать объект вручную CEvent , передайте TRUE параметр bManualReset во время построения.

Чтобы использовать CEvent объект, создайте CEvent объект при необходимости. Укажите имя события, на которое вы хотите ждать, а также укажите, что приложение должно изначально владеть им. Затем вы можете получить доступ к событию, когда конструктор возвращается. Вызов SetEvent сигнала (сделать доступным) объект события, а затем вызов Unlock , когда вы закончите доступ к управляемому ресурсу.

Альтернативным способом использования CEvent объектов является добавление переменной типа CEvent в качестве элемента данных в класс, который требуется контролировать. Во время построения управляемого объекта вызовите конструктор CEvent элемента данных и укажите, сигнализирует ли событие изначально, а также укажите нужный тип объекта события, имя события (если оно будет использоваться через границы процесса) и все нужные атрибуты безопасности.

Чтобы получить доступ к ресурсу, управляемому CEvent объектом таким образом, сначала создайте переменную любого типа или типа CMultiLock CSingleLock в методе доступа ресурса. Затем вызовите Lock метод lock объекта (например, CMultiLock::Lock). На этом этапе поток получит доступ к ресурсу, подождите, пока ресурс будет освобожден и получите доступ, или дождитесь освобождения ресурса, времени ожидания и сбоя доступа к ресурсу. В любом случае ресурс был доступ к ресурсу в потокобезопасном режиме. Чтобы освободить ресурс, вызовите SetEvent сигнал объекта события, а затем используйте Unlock метод lock объекта (например, CMultiLock::Unlockили позволить lock объекту выйти из области).

Дополнительные сведения об использовании CEvent объектов см. в разделе "Многопоточность: использование классов синхронизации".

Пример

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

Иерархия наследования

CObject

CSyncObject

CEvent

Требования

Заголовок: afxmt.h

CEvent::CEvent

Создает именованный или неименованный CEvent объект.

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

Параметры

bInitiallyOwn
Если TRUEпоток для CMultilock объекта или CSingleLock объекта включен. В противном случае все потоки, желающие получить доступ к ресурсу, должны ждать.

bManualReset
Если TRUEуказывает, что объект события является событием вручную, в противном случае объект события является автоматическим.

lpszName
Имя объекта CEvent. Необходимо указать, если объект будет использоваться через границы процесса. Если имя соответствует существующему событию, конструктор создает новый CEvent объект, который ссылается на событие этого имени. Если имя соответствует существующему объекту синхронизации, который не является событием, построение завершится ошибкой. Если NULLимя будет иметь значение NULL.

lpsaAttribute
Атрибуты безопасности для объекта события. Полное описание этой структуры см SECURITY_ATTRIBUTES . в пакете SDK для Windows.

Замечания

Чтобы получить доступ к объекту CEvent CMultiLock или освободить его, создайте объект или CSingleLock объект и Unlock вызовите функции-членыLock.

Чтобы изменить состояние CEvent объекта на сигнал (потоки не нужно ждать), вызов SetEvent или PulseEvent. Чтобы задать состояние CEvent объекта незначаемой (потоки должны ждать), вызов ResetEvent.

Внимание

После создания CEvent объекта используйте для GetLastError обеспечения того, чтобы мьютекс еще не существовал. Если мьютекс существовал неожиданно, он может указать, что процесс изгоя скватируется и может намереваться использовать мьютекс злонамеренно. В этом случае рекомендуется закрыть дескриптор и продолжить, как если бы при создании объекта произошел сбой.

CEvent::PulseEvent

Задает состояние события для сигнала (доступно), освобождает все потоки ожидания и сбрасывает его на незначаемые (недоступные) автоматически.

BOOL PulseEvent();

Возвращаемое значение

Ненулевое значение, если функция была успешной; в противном случае — 0.

Замечания

Если событие выполняется вручную, все потоки ожидания освобождаются, событие устанавливается как незначаемое и PulseEvent возвращается. Если событие является автоматическим, освобождается один поток, событие устанавливается как незначаемое и PulseEvent возвращается.

Если потоки не ожидаются, или потоки не могут быть освобождены немедленно, PulseEvent задает состояние события незначальным и возвращается.

PulseEvent использует базовую функцию Win32 PulseEvent , которая может быть мгновенно удалена из состояния ожидания вызовом асинхронной процедуры в режиме ядра. PulseEvent Поэтому ненадежно и не должно использоваться новыми приложениями. Дополнительные сведения см. по функции PulseEvent.

CEvent::ResetEvent

Задает состояние события незначаемым, пока явно не задано SetEvent сигналом функции-члена.

BOOL ResetEvent();

Возвращаемое значение

Ненулевое значение, если функция была успешной; в противном случае — 0.

Замечания

Это приводит ко всем потокам, желающим получить доступ к этому событию, ожидать.

Эта функция-член не используется автоматическими событиями.

CEvent::SetEvent

Задает состояние события для сигнала, освобождая все потоки ожидания.

BOOL SetEvent();

Возвращаемое значение

Ненулевое значение, если функция выполнена успешно, в противном случае — значение 0.

Замечания

Если событие выполняется вручную, событие будет оставаться сигналом до вызова ResetEvent . В этом случае можно освободить несколько потоков. Если событие является автоматическим, событие будет оставаться сигналом до выпуска одного потока. Затем система установит состояние события незначаемой. Если потоки не ожидают, состояние остается сигналом до тех пор, пока не будет освобожден один поток.

CEvent::Unlock

Освобождает объект события.

BOOL Unlock();

Возвращаемое значение

Ненулевое значение, если поток принадлежит объекту события и событие является автоматическим; в противном случае — 0.

Замечания

Эта функция-член вызывается потоками, которые в настоящее время имеют автоматическое событие, чтобы освободить его после их завершения, если их lock объект должен использоваться повторно. lock Если объект не используется повторно, эта функция будет вызываться деструктором lock объекта.

См. также

CSyncObject Класс
Диаграмма иерархии