异步过程调用(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,完成后再继续线程的原来执行。1
APIAPC对象:为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回调函数。2
并发控制在计算机科学,特别是程序设计、操作系统、多处理机和数据库等领域,并发控制(英语:Concurrency control)是确保及时纠正由并发操作导致的错误的一种机制。1
异步IO异步IO是计算机操作系统对输入输出的一种处理方式:发起IO请求的线程不等IO操作完成,就继续执行随后的代码,IO结果用其他方式通知发起IO请求的程序。与异步IO相对的是更为常见的“同步(阻塞)IO”:发起IO请求的线程不从正在调用的IO操作函数返回(即被阻塞),直至IO操作完成。1
本词条内容贡献者为:
王沛 - 副教授、副研究员 - 中国科学院工程热物理研究所