APC (Asynchronous Procedure Call)

喜你入骨 提交于 2019-12-01 07:09:34

系统创建新线程时,会同时创建与这个线程相关联的队列,即异步过程调用(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的回调函数是在原线程休眠时在原线程上调用。

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!