Bagikan melalui


Menggunakan Timer yang Dapat Diantisipasi dengan Panggilan Prosedur Asinkron

Contoh berikut mengaitkan fungsi panggilan prosedur asinkron (APC), juga dikenal sebagai rutinitas penyelesaian, dengan timer yang dapat ditunggu saat timer diatur. Alamat rutinitas penyelesaian adalah parameter keempat untuk fungsi SetWaitableTimer . Parameter kelima adalah penunjuk kekosongan yang dapat Anda gunakan untuk meneruskan argumen ke rutinitas penyelesaian.

Rutinitas penyelesaian akan dijalankan oleh utas yang sama yang disebut SetWaitableTimer. Utas ini harus dalam keadaan yang dapat diperingatkan untuk menjalankan rutinitas penyelesaian. Ini mencapai ini dengan memanggil fungsi SleepEx , yang merupakan fungsi yang dapat diperingatkan.

Setiap utas memiliki antrean APC. Jika ada entri dalam antrean APC utas pada saat salah satu fungsi yang dapat diperingatkan dipanggil, utas tidak ditidur. Sebaliknya, entri dihapus dari antrean APC dan rutinitas penyelesaian dipanggil.

Jika tidak ada entri dalam antrean APC, utas ditangguhkan hingga penantian terpenuhi. Penantian dapat dipenuhi dengan menambahkan entri ke antrean APC, dengan batas waktu, atau dengan handel yang menjadi sinyal. Jika penantian dipenuhi oleh entri dalam antrean APC, utas terbangun dan rutinitas penyelesaian dipanggil. Dalam hal ini, nilai pengembalian fungsi WAIT_IO_COMPLETION.

Setelah rutinitas penyelesaian dijalankan, sistem memeriksa entri lain dalam antrean APC untuk diproses. Fungsi yang dapat diperingatkan hanya akan kembali setelah semua entri APC diproses. Oleh karena itu, jika entri ditambahkan ke antrean APC lebih cepat daripada yang dapat diproses, ada kemungkinan bahwa panggilan ke fungsi yang dapat diperingatkan tidak akan pernah kembali. Ini terutama dimungkinkan dengan timer yang dapat ditunggu, jika periode lebih pendek dari jumlah waktu yang diperlukan untuk menjalankan rutinitas penyelesaian.

Saat Anda menggunakan timer yang dapat di tunggu dengan APC, utas yang mengatur timer tidak boleh menunggu pada handel timer. Dengan demikian, Anda akan menyebabkan utas bangun sebagai akibat dari timer menjadi sinyal daripada sebagai hasil dari entri yang ditambahkan ke antrean APC. Akibatnya, utas tidak lagi dalam keadaan yang dapat diperingatkan dan rutinitas penyelesaian tidak dipanggil. Dalam kode berikut, panggilan ke SleepEx membangkitkan utas saat entri ditambahkan ke antrean APC utas setelah timer diatur ke status bersinyali.

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

Menggunakan Objek Timer yang Dapat Diantisipasi