Megosztás:


Várakozási időzítők használata aszinkron eljáráshívással

Az alábbi példa egy aszinkron eljáráshívási (APC) függvényt, más néven befejezési rutint társít egy várakozó időzítőhöz, az időzítő beállításakor. A befejezési rutin címe a SetWaitableTimer függvény negyedik paramétere. Az ötödik paraméter egy üres mutató, amellyel argumentumokat adhat át a befejezési rutinnak.

A befejezési rutint ugyanaz a szál hajtja végre, amely SetWaitableTimernéven fut. Ennek a szálnak riasztási állapotban kell lennie a befejezési rutin végrehajtásához. Ezt úgy hajtja végre, hogy meghívja a SleepEx függvényt, amely egy riasztásra alkalmas függvény.

Minden szálhoz egy APC-sor tartozik. Ha egy bejegyzés szerepel a szál APC-üzenetsorában az egyik riasztási függvény meghívásakor, a szál nem lesz alvó állapotba helyezve. Ehelyett a rendszer eltávolítja a bejegyzést az APC-üzenetsorból, és meghívja a befejezési rutint.

Ha nincs bejegyzés az APC-üzenetsorban, a rendszer felfüggeszti a szálat, amíg a várakozás nem teljesül. A várakozást úgy lehet kielégíteni, ha egy bejegyzést ad hozzá az APC-üzenetsorhoz, időtúllépéssel vagy egy jelzéssé váló fogóponttal. Ha a várakozást az APC-üzenetsor egyik bejegyzése kielégíti, a folyamat felébred, és a befejezési rutin meghívása történik. Ebben az esetben a függvény visszatérési értéke WAIT_IO_COMPLETION.

A befejezési rutin végrehajtása után a rendszer egy másik bejegyzést keres az APC-üzenetsorban a feldolgozáshoz. A riasztható függvény csak az összes APC-bejegyzés feldolgozása után tér vissza. Ezért, ha a bejegyzések gyorsabban kerülnek az APC-üzenetsorba, mint ahogy feldolgozhatók, lehetséges, hogy egy riasztás érzékeny függvény meghívása soha nem tér vissza. Ez különösen lehetséges várakozási időzítőkkel, ha a periódus rövidebb, mint a befejezési rutin végrehajtásához szükséges idő.

Ha várakozó időzítőt használ egy APC-vel, az időzítőt beállító szálnak nem szabad várnia az időzítő fogantyújára. Ezzel azt okozhatja, hogy a szál az időzítő jelzése helyett az APC-üzenetsorhoz hozzáadott bejegyzés miatt ébred fel. Ennek eredményeképpen a szál már nem érzékeny a riasztásokra, és a befejezési rutint nem hívják meg. Az alábbi kódban a SleepEx hívása akkor ébreszti fel a szálat, amikor egy bejegyzést adnak a szál APC-üzenetsorához, miután az időzítőt a jelzett állapotra állították.

#define UNICODE 1
#define _UNICODE 1

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#define _SECOND 10000000

typedef struct _MYDATA {
   LPCTSTR szText;
   DWORD dwValue;
} MYDATA;

VOID CALLBACK TimerAPCProc(
   LPVOID lpArg,               // Data value
   DWORD dwTimerLowValue,      // Timer low value
   DWORD dwTimerHighValue )    // Timer high value

{
   // Formal parameters not used in this example.
   UNREFERENCED_PARAMETER(dwTimerLowValue);
   UNREFERENCED_PARAMETER(dwTimerHighValue);

   MYDATA *pMyData = (MYDATA *)lpArg;

   _tprintf( TEXT("Message: %s\nValue: %d\n\n"), pMyData->szText,
          pMyData->dwValue );
   MessageBeep(0);

}

int main( void ) 
{
   HANDLE          hTimer;
   BOOL            bSuccess;
   __int64         qwDueTime;
   LARGE_INTEGER   liDueTime;
   MYDATA          MyData;

   MyData.szText = TEXT("This is my data");
   MyData.dwValue = 100;

   hTimer = CreateWaitableTimer(
           NULL,                   // Default security attributes
           FALSE,                  // Create auto-reset timer
           TEXT("MyTimer"));       // Name of waitable timer
   if (hTimer != NULL)
   {
      __try 
      {
         // Create an integer that will be used to signal the timer 
         // 5 seconds from now.
         qwDueTime = -5 * _SECOND;

         // Copy the relative time into a LARGE_INTEGER.
         liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );
         liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );

         bSuccess = SetWaitableTimer(
            hTimer,           // Handle to the timer object
            &liDueTime,       // When timer will become signaled
            2000,             // Periodic timer interval of 2 seconds
            TimerAPCProc,     // Completion routine
            &MyData,          // Argument to the completion routine
            FALSE );          // Do not restore a suspended system

         if ( bSuccess ) 
         {
            for ( ; MyData.dwValue < 1000; MyData.dwValue += 100 ) 
            {
               SleepEx(
                  INFINITE,     // Wait forever
                  TRUE );       // Put thread in an alertable state
            }

         } 
         else 
         {
            printf("SetWaitableTimer failed with error %d\n", GetLastError());
         }

      } 
      __finally 
      {
         CloseHandle( hTimer );
      }
   } 
   else 
   {
      printf("CreateWaitableTimer failed with error %d\n", GetLastError());
   }

   return 0;
}

Várakozó időzítőobjektumok használata