系统创建新线程时,会同时创建与这个线程相关联的队列,即异步过程调用(APC)的队列。
一些异步操作可以通过加入APC来实现,比如我现在学习的IO请求/完成。
BOOL ReadFileEx(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
IO完成时,系统向该线程的APC队列中加入一项,包含lpCompleteionRoutine和lpOverlapped。当线程处于非执行态且是可提醒的状态时,系统会取出APC中的项,并让线程执行其中的回调函数。这个动作会重复到队列空,我猜想可能还会被线程正常唤醒打断。
非执行态是线程调用了等待、休眠函数,像
DWORD SleepEx(DWORD dwMilliseconds, bool bAlertable );
DWORD WaitForSigleObjectEx(HANDLE hObject,DWORD dwMilliseconds,bool bAlertable);
bAlertable=true; 是可提醒状态!
另一段APC call的代码,是一个waitableTimer的例子。
#include <iostream> #include<process.h> #include<Windows.h> #include<tchar.h> #include<string.h> void APIENTRY TimerAPCRoutine(PVOID pvArgToCompleteRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue); void SomeFunc() { HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL); LARGE_INTEGER li = { 0 }; SetWaitableTimer(hTimer, &li, 5000, TimerAPCRoutine, NULL, false); SleepEx(INFINITE, true); CloseHandle(hTimer); } void APIENTRY TimerAPCRoutine(PVOID pvArgToCompleteRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue) { FILETIME ftUTC, ftLocal; SYSTEMTIME st; TCHAR szBuf[256]; ftUTC.dwHighDateTime = dwTimerHighValue; ftUTC.dwLowDateTime = dwTimerLowValue; FileTimeToLocalFileTime(&ftUTC, &ftLocal); FileTimeToSystemTime(&ftLocal, &st); GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szBuf, _countof(szBuf)); _tcscat_s(szBuf, _countof(szBuf), " "); GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, _tcschr(szBuf, TEXT('