The first time I saw APC, that is, asynchronous Process calling, I didn't understand what kind of mechanism it was.
Let's take a look again today, and then combine some simple test code and search materials to understand what is going on.
First, let's briefly describe this "wait-time kernel object ".
The definition is as follows:
Wait timer objects are such kernel objects that are triggered at a specified time or once every time. They are usually used to perform some operations at a certain time.
Related APIs (for specific parameters, see MSDN ):
Create a wait Timer: CreateWaitableTimer
Get the handle of an existing timer that can be waited: OpenWaitableTimer
SetWaitableTimer
Wait for the timer to add APC call
Miscrosoft allows the timer to put an asynchronous process call (Asynchronnous procedure call, APC) into the queue of the call thread. Put this asynchronous process call into the queue of the calling thread. It is a parameter that calls SetWaitableTimer and uses the type PTIMERAPCROUTINE. this parameter is actually a function pointer type, so the address of the asynchronous process is uploaded here. To call these asynchronous processes by a thread, the thread must also be in the reminder state, that is, the waiting state to enter by calling SleepEx, WaitForSingleObjectEx, WaitForMultipleObjectEx, and MsgWaitForMultipleObjectEx. Each of these functions has a parameter that indicates whether the thread enters the reminder status.
Sample Code:
# Define _ WIN32_WINNT 0x0400 # include <windows. h> # include <windowsx. h> // only some macros are included, excluding some Type Definitions # include <tchar. h> # include <stdio. h> void apientry values (PVOID values, DWORD dwTimerLowValue, DWORD dwTimerHighValue); int main (void) {HANDLE hTimer; LARGE_INTEGER li; hTimer = CreateWaitableTimer (NULL, FALSE, NULL ); const int nTimerUnitsPerSecond = 10000000; li. quadPart =-(5 * nTimerUnitsPerSecond); // negative value indicates the relative time SetWaitableTimer (hTimer, & li, 6*60*60*1000, TimerAPCRoutine, NULL, FALSE ); printf ("Main Thread Sleep for INFINE \ n"); SleepEx (INFINITE, TRUE); printf ("Main Thread Wake Up \ n"); CloseHandle (hTimer ); return 0;} void apientry TimerAPCRoutine (PVOID pvArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue) {printf ("APC Fuction \ n"); return ;}
The general execution process of the program is to create a wait timer and add an asynchronous process call, and then call SleepEx to enter the reminder status. When the timer is triggered, the thread that calls SetWaitableTimer will call one of the APC queues, that is, the address of the function we just passed in. After the execution is completed, the thread returns from the SleepEx call. This is probably the process.
PS: If the APC queue is not empty when SleepEx is called, the thread does not sleep, but calls an item in the APC queue until the APC queue is empty. When calling functions that sleep a thread, these functions will suspend the thread only when none of the APC queue of the thread is available.
It is also worth mentioning that this mechanism allows the wait timer to add APC calls, a bit similar to the signal processing function for processing alarm signals in Linux.