异步过程调用

异步过程调用（asynchronous procedure call）是函数（过程）在特定线程中被异步执行。在Microsoft Windows操作系统中, APC是一种并发机制，用于异步IO或者定时器。

分类
Windows NT操作系统中有3种APC：
内核模式特殊APC：相应的APC函数为内核函数。在IRQL =APC_LEVEL级上有可调度的活动时，执行此类APC。会抢先所有的用户模态以及IRQL = PASSIVE_LEVEL的内核模态下的代码的执行。
内核模式常规APC：在所有的内核模式特殊APC执行完毕后，内核模式常规APC在IRQL = PASSIVE_LEVEL下开始执行。会抢先所有的用户模式代码的执行。用于文件系统。
用户模式APC：是指相应的 APC 函数位于用户空间、在用户空间执行。线程处于alertable wait状态该APC才可以被调度执行。用户模式下调用系统API如SleepEx, SignalObjectAndWait,WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectEx等，可以使线程进入alertable状态。这些API函数最终都是调用了内核中的KeWaitForSingleObject, KeWaitForMultipleObjects,KeWaitForMutexObject, KeDelayExecutionThread, KeTestAlertThread等函数。线程在alertable wait状态所有内核模式API执行完毕，返回用户模式时，内核转去执行APC，完成后再继续线程的原来执行。

API
APC对象：为struct KAPC类型。每个APC对象必须要包含一个KernelRoutine函数指针，当这个APC被操作系统的APC dispatcher执行时，该例程首先被执行。用户模式APCs必须包含一个NormalRoutine函数指针，所指的函数在用户内存区域。内核模式常规APC也必须包含一个NormalRoutine，但运行在内核模式（即_KAPC.ApcMode==KernelMode）。内核模式特殊APC的NormalRoutine为空。任意类型的APC都可以定义一个RundownRoutine，所指函数在内核内存区域，当系统需要释放APC队列的内容时（例如线程退出时）被调用。
每个线程有两个APC队列，分为用户APC队列和内核APC队列。
QueueUserAPC: 应用程序把APC放入一个线程的用户模式APC队列中；
KeInitializeApc 处理异步IO的设备驱动程序用这个函数来初始化APC对象（为struct KAPC类型)。如果函数参数NormalRoutine为NULL，那么生成的是内核模式特殊APC对象；如果参数NormalRoutine为NULL且参数ApcMode的值是KernelMode，那么生成的是内核模式常规APC对象；否则生成用户模式APC对象。
KeInsertQueueApc  把完成初始化的APC对象存放到目标线程的APC队列中
KiInsertQueueApc  实际完成插入到队列中的操作
KiDeliverApc  即操作系统APC派发器子程序。投递一个挂起的（pending）APC到目标线程。KiDeliverApc每处理完一个User APC就把UserApcPending清零，所以User APCs在返回用户空间时还是只能投递一次.
KiInitializeUserApc:在从内核态返回到用户态以执行用户模式APC时，修改环境以准备好由KeUserApcDispatcher调用User APC回调函数.

参考文献

Microsoft Windows