Bagikan melalui


Menggunakan Timer yang Dapat Ditunda 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 fungsiSetWaitableTimer. Parameter kelima adalah penunjuk kekosongan yang dapat Anda gunakan untuk meneruskan argumen ke rutinitas penyelesaian.

Rutinitas penyelesaian akan dijalankan oleh utas yang sama yang memanggil SetWaitableTimer. Utas ini harus dalam status yang dapat diperingatkan untuk menjalankan rutinitas penyelesaian. Ini mencapainya 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 menerima sinyal peringatan dipanggil, utas tidak diistirahatkan. Sebagai gantinya, entri dihapus dari antrean APC dan prosedur penyelesaian dipanggil.

Jika tidak ada entri dalam antrean APC, utas digantung sementara hingga penantian terpenuhi. Penantian dapat dipenuhi dengan menambahkan entri ke antrean APC, dengan batas waktu, atau dengan handel yang menjadi sinyal. Jika penantian terpenuhi 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 memberikan peringatan akan kembali hanya 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 ditunggu dengan APC, utas yang mengatur timer tidak boleh menunggu pada handle timer. Dengan demikian, Anda akan menyebabkan utas terbangun akibat timer yang memberi sinyal, bukan karena ada entri yang ditambahkan ke antrean APC. Akibatnya, utas tidak lagi dalam keadaan siaga dan rutinitas penyelesaian tidak dipanggil. Dalam kode berikut, panggilan ke SleepEx membangunkan utas saat entri ditambahkan ke antrean APC utas setelah timer diubah ke keadaan disinyalir.

#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 Ditunda