系统创建新线程时,会同时创建与这个线程相关联的队列,即异步过程调用(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('\0')), (int)(_countof(szBuf) - _tcslen(szBuf)));
- MessageBox(NULL, szBuf, TEXT("Timer went off at ..."), MB_OK);
- }
- int wmain(int argc, wchar_t* argv[])
- {
- SomeFunc();
- char c;
- std::cin >> c;
- return 0;
- }
线程跑到APC回调函数时,

总结:
APC是由系统管理的与线程相关的队列,可用来执行异步操作。
APC的回调函数是在原线程休眠时在原线程上调用。