Sdílet prostřednictvím


CEvent Třída

Představuje událost, což je synchronizační objekt, který umožňuje jednomu vláknu upozornit jiné, že došlo k události.

Syntaxe

class CEvent : public CSyncObject

Členové

Veřejné konstruktory

Název Popis
CEvent::CEvent CEvent Vytvoří objekt.

Veřejné metody

Název Popis
CEvent::PulseEvent Nastaví událost na dostupnou (signalovanou), uvolní čekací vlákna a nastaví událost na nedostupnou (nepřiřazenou).
CEvent::ResetEvent Nastaví událost na nedostupnou (nepřiřazenou).
CEvent::SetEvent Nastaví událost na dostupnou (signalovanou) a uvolní všechna čekající vlákna.
CEvent::Unlock Uvolní objekt události.

Poznámky

Události jsou užitečné, když vlákno musí vědět, kdy má provést úlohu. Například vlákno, které kopíruje data do archivu dat, musí být upozorněno, když jsou k dispozici nová data. Pomocí objektu CEvent upozorňovat vlákno kopírování, když jsou k dispozici nová data, může vlákno provést svou úlohu co nejdříve.

CEvent objekty mají dva typy: ruční a automatické.

Automatický CEvent objekt se po uvolnění alespoň jednoho vlákna automaticky vrátí do nesignalovaného (nedostupného) stavu. Ve výchozím nastavení je objekt automatický, CEvent pokud neprojdete TRUE parametrem bManualReset během výstavby.

Ruční CEvent objekt zůstane ve stavu nastaveném SetEvent nebo ResetEvent dokud se jiná funkce nevolá. Chcete-li vytvořit ruční CEvent objekt, předejte TRUE parametr bManualReset během sestavování.

Chcete-li použít CEvent objekt, vytvořte CEvent objekt v případě potřeby. Zadejte název události, na kterou chcete čekat, a také určete, že vaše aplikace by ji měla původně vlastnit. Pak můžete získat přístup k události, když konstruktor vrátí. Volání SetEvent signálu (zpřístupnění) objektu události a následné volání Unlock po dokončení přístupu k řízenému prostředku.

Alternativní metodou použití CEvent objektů je přidání proměnné typu CEvent jako datového člena do třídy, kterou chcete řídit. Během vytváření řízeného objektu zavolejte konstruktor datového CEvent členu a určete, zda je událost původně signalována, a také zadejte typ objektu události, který chcete, název události (pokud se použije přes hranice procesu) a všechny požadované atributy zabezpečení.

Pokud chcete získat přístup k prostředku řízenému objektem CEvent tímto způsobem, nejprve vytvořte proměnnou typu CSingleLock nebo typu CMultiLock v metodě přístupu vašeho prostředku. Pak zavolejte Lock metodu objektu lock (například CMultiLock::Lock). V tomto okamžiku vaše vlákno získá přístup k prostředku, počká na uvolnění a získání přístupu, nebo počkejte, až se prostředek uvolní, vyprší časový limit a nepodaří se získat přístup k prostředku. V každém případě byl váš prostředek přístupný bezpečným způsobem s vlákny. Pokud chcete uvolnit prostředek, zavolejte SetEvent objekt události a pak použijte Unlock metodu objektu lock (například CMultiLock::Unlock) nebo nechte lock objekt vypadnout mimo rozsah.

Další informace o tom, jak používat CEvent objekty, naleznete v tématu Multithreading: Jak používat synchronizační třídy.

Příklad

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

Hierarchie dědičnosti

Objekt CObject

CSyncObject

CEvent

Požadavky

Záhlaví: afxmt.h

CEvent::CEvent

Vytvoří pojmenovaný nebo nepojmenovaný CEvent objekt.

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

Parametry

bInitiallyOwn
Pokud TRUEje vlákno pro CMultilock objekt nebo CSingleLock objekt povoleno. Jinak musí všechna vlákna, která chtějí získat přístup k prostředku, počkat.

bManualReset
Pokud TRUEurčuje, že objekt události je ruční událostí, jinak je objekt události automatickou událostí.

lpszName
Název objektu CEvent . Je nutné zadat, pokud se objekt použije přes hranice procesu. Pokud název odpovídá existující události, konstruktor vytvoří nový CEvent objekt, který odkazuje na událost tohoto názvu. Pokud název odpovídá existujícímu objektu synchronizace, který není událostí, konstrukce selže. Pokud NULLbude mít název hodnotu null.

lpsaAttribute
Atributy zabezpečení pro objekt události. Úplný popis této struktury najdete SECURITY_ATTRIBUTES v sadě Windows SDK.

Poznámky

Pokud chcete získat přístup k objektu nebo ho CEvent uvolnit, vytvořte CMultiLock nebo CSingleLock zavolejte jeho Lock a Unlock členské funkce.

Chcete-li změnit stav objektu CEvent na signál (vlákna nemusí čekat), volání SetEvent nebo PulseEvent. Chcete-li nastavit stav objektu CEvent na nonsignaled (vlákna musí čekat), volání ResetEvent.

Důležité

Po vytvoření objektu CEvent se ujistěte GetLastError , že objekt mutex ještě neexistuje. Pokud mutex existoval neočekávaně, může to znamenat, že neautorský proces je squatting a může být v úmyslu používat mutex se zlými úmysly. V takovém případě je doporučeným postupem při vědomí zabezpečení zavřít popisovač a pokračovat, jako by při vytváření objektu došlo k chybě.

CEvent::PulseEvent

Nastaví stav události tak, aby signalizoval (k dispozici), uvolní všechna čekající vlákna a automaticky ho resetuje na nepřiřazené (nedostupné).

BOOL PulseEvent();

Návratová hodnota

Nenulové, pokud byla funkce úspěšná; jinak 0.

Poznámky

Pokud je událost ruční, uvolní se všechna čekající vlákna, událost je nastavena na nepřiřazené a PulseEvent vrátí se. Pokud je událost automatická, uvolní se jedno vlákno, událost je nastavena na nonsignaled a PulseEvent vrátí.

Pokud nečekají žádná vlákna nebo nelze okamžitě uvolnit žádná vlákna, PulseEvent nastaví stav události na nepřiřazené a vrátí.

PulseEvent používá základní funkci Win32 PulseEvent , která může být momentálně odebrána ze stavu čekání asynchronním voláním procedury v režimu jádra. PulseEvent Proto je nespolehlivý a neměl by je používat nové aplikace. Další informace najdete v PulseEvent této funkci.

CEvent::ResetEvent

Nastaví stav události na nepřiřazené, dokud explicitně nenastaví signál členové SetEvent funkce.

BOOL ResetEvent();

Návratová hodnota

Nenulové, pokud byla funkce úspěšná; jinak 0.

Poznámky

To způsobí, že všechna vlákna, která chtějí získat přístup k této události, čekají.

Tato členová funkce se nepoužívá automatickými událostmi.

CEvent::SetEvent

Nastaví stav události na signál a uvolní všechna čekající vlákna.

BOOL SetEvent();

Návratová hodnota

Nenulové, pokud byla funkce úspěšná, jinak 0.

Poznámky

Pokud je událost ruční, událost zůstane signalizovat, dokud ResetEvent se nevolá. V tomto případě lze uvolnit více než jedno vlákno. Pokud je událost automatická, událost zůstane signalizovat, dokud se nevyvolá jedno vlákno. Systém pak nastaví stav události na nepřiřazené. Pokud nečekají žádná vlákna, stav zůstane signalován, dokud se nevyvolá jedno vlákno.

CEvent::Unlock

Uvolní objekt události.

BOOL Unlock();

Návratová hodnota

Nenulové, pokud vlákno vlastní objekt události a událost je automatická událost; jinak 0.

Poznámky

Tato členová funkce je volána vlákny, která aktuálně vlastní automatickou událost, aby ji po dokončení uvolnila, pokud se má jejich lock objekt znovu použít. lock Pokud objekt nebude znovu použit, bude tato funkce volána lock destruktoru objektu.

Viz také

CSyncObject Třída
Graf hierarchie