系統創建新線程時,會同時創建與這個線程相關聯的隊列,即非同步過程調用(APC)的隊列。 一些非同步操作可以通過加入APC來實現,比如我現在學習的IO請求/完成。 IO完成時,系統向該線程的APC隊列中加入一項,包含lpCompleteionRoutine和lpOverlapped。當線程處於非執行態且是 ...
系統創建新線程時,會同時創建與這個線程相關聯的隊列,即非同步過程調用(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的回調函數是在原線程休眠時在原線程上調用。