执行APC直到队列为空。当您从APC系统检查返回的代码是插入另一个APC时 - 如果是 - 接下来APC将执行,直到没有更多的APC插入线程。这SleepEx
(或任何其它报警等待API)返回控制你
的APC在接下来的方式执行之后 - 当你调用某个API(SleepEx
,MsgWaitForMultipleObjectsEx
,WaitForSingleObjectEx
,WaitForMultipleObjectsEx
..与功能的bAlertable参数设置为TRUE)内核检查是在线程对象中插入APC。如果是 - 内核将用户模式线程上下文复制到堆栈,而不是更改线程上下文(用户模式返回地址设置为ntdll.KiUserApcDispatcher
)并返回。因为结果代码不是从他进入内核的地方返回(如果是SleepEx
这是内部调用的ZwDelayExecution
),而是返回到KiUserApcDispatcher
。此api执行APC然后致电ZwContinue
。这个API声明:
NTSYSAPI NTSTATUS NTAPI ZwContinue(PCONTEXT Context, BOOLEAN TestAlert);
中使用保存在栈线程上下文中,返回点,从中可报警API被称为地方文脉和TestAlert
指定是否应检查插入额外的APC。如果调用ZwContinue
与TestAlert == FALSE
系统将不再检查线程队列中的APC,直到您自己没有调用SleepEx
或其他特定的api为止 - 因此将执行完全1个APC。但在KiUserApcDispatcher
TestAlert
硬编码为TRUE
- 你很容易可以自己看看,如果了解汇编代码(KiUserApcDispatcher
很小)
这是不可知的。调用QueueUserApc()的线程不知道可警告线程是否已恢复。在可恢复之前,可警告线程是否在队列中运行并不重要。 –
@HansPassant我的问题不是来自QueueUserApc的观点,而是SleepEx如何工作。 –
@HansPassant - 你错了。这可能是未记录的,但已知 - 当从* APC * - 系统检查线程返回时线程中插入了额外的APC。如果是的话 - 执行它。所以这将在循环中,直到线程没有更多的APC – RbMm