Usando temporizadores de espera com uma chamada de procedimento assíncrona
O exemplo a seguir associa uma função de de chamada de procedimento assíncrono (APC), também conhecida como rotina de conclusão, a um temporizador de espera quando o temporizador é definido. O endereço da rotina de conclusão é o quarto parâmetro da função SetWaitableTimer. O quinto parâmetro é um ponteiro de tipo void que pode ser usado para passar argumentos para a rotina de conclusão.
A rotina de conclusão será executada pelo mesmo thread chamado SetWaitableTimer. Esse thread deve estar em um estado alertável para executar a rotina de conclusão. Ele faz isso chamando a função SleepEx, que é uma função alertável.
Cada thread tem uma fila APC. Se houver uma entrada na fila APC do thread no momento em que uma das funções alertáveis for chamada, o thread não será colocado em suspensão. Em vez disso, a entrada é removida da fila APC e a rotina de conclusão é chamada.
Se não existir nenhuma entrada na fila APC, a thread será suspensa até que a condição de espera seja satisfeita. A espera pode ser satisfeita adicionando uma entrada à fila APC, por um tempo limite ou por um identificador sendo sinalizado. Se a espera for satisfeita por uma entrada na fila APC, o thread será despertado e a rotina de conclusão será chamada. Nesse caso, o valor de retorno da função é WAIT_IO_COMPLETION.
Depois que a rotina de conclusão é executada, o sistema verifica se há outra entrada na fila APC a ser processada. Uma função alertável retornará somente depois que todas as entradas APC tiverem sido processadas. Portanto, se as entradas forem adicionadas à fila APC mais rapidamente do que podem ser processadas, é possível que uma chamada a uma função alertável nunca retorne. Isso é especialmente possível com temporizadores de espera, se o período for menor do que a quantidade de tempo necessária para executar a rotina de conclusão.
Quando você estiver usando um temporizador de espera com um APC, o thread que define o temporizador não deve esperar na alça do temporizador. Ao fazer isso, faria com que o fio acordasse como resultado de o temporizador ser ativado em vez de uma entrada ser adicionada à fila APC. Como resultado, o thread não está mais em um estado alertável e a rotina de conclusão não é chamada. No código a seguir, a chamada para SleepEx desperta o thread quando uma entrada é adicionada à fila APC do thread depois que o temporizador é definido para o estado sinalizado.
#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;
}
Tópicos relacionados