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;
}
Topik terkait