2017-09-14 16 views
-1

这与我的former question有点相关,关于SleepEx实际如何工作。 The docs表示只要APC排队并且APC可能会在线程已经执行APC时保持排队,那么执行SleepEx的线程就会恢复。SleepEx期间处理多少个APC?

线程继续执行APC多长时间?是否直到队列被检查时为空,并且在那一刻SleepEx将控制权返回给调用者?或者只有该线程正好执行一个APC,那么SleepEx返回并且APC的另一个执行需要SleepEx再被调用一次?

我有这样的感觉,即APC一直执行到队列第一次为空。谢谢!

+1

这是不可知的。调用QueueUserApc()的线程不知道可警告线程是否已恢复。在可恢复之前,可警告线程是否在队列中运行并不重要。 –

+0

@HansPassant我的问题不是来自QueueUserApc的观点,而是SleepEx如何工作。 –

+0

@HansPassant - 你错了。这可能是未记录的,但已知 - 当从* APC * - 系统检查线程返回时线程中插入了额外的APC。如果是的话 - 执行它。所以这将在循环中,直到线程没有更多的APC – RbMm

回答

2

执行APC直到队列为空。当您从APC系统检查返回的代码是插入另一个APC时 - 如果是 - 接下来APC将执行,直到没有更多的APC插入线程。这SleepEx(或任何其它报警等待API)返回控制你


的APC在接下来的方式执行之后 - 当你调用某个API(SleepExMsgWaitForMultipleObjectsExWaitForSingleObjectExWaitForMultipleObjectsEx ..与功能的bAlertable参数设置为TRUE)内核检查是在线程对象中插入APC。如果是 - 内核将用户模式线程上下文复制到堆栈,而不是更改线程上下文(用户模式返回地址设置为ntdll.KiUserApcDispatcher)并返回。因为结果代码不是从他进入内核的地方返回(如果是SleepEx这是内部调用的ZwDelayExecution),而是返回到KiUserApcDispatcher。此api执行APC然后致电ZwContinue。这个API声明:

NTSYSAPI NTSTATUS NTAPI ZwContinue(PCONTEXT Context, BOOLEAN TestAlert); 

中使用保存在栈线程上下文中,返回点,从中可报警API被称为地方文脉和TestAlert指定是否应检查插入额外的APC。如果调用ZwContinueTestAlert == FALSE系统将不再检查线程队列中的APC,直到您自己没有调用SleepEx或其他特定的api为止 - 因此将执行完全1个APC。但在KiUserApcDispatcherTestAlert硬编码为TRUE - 你很容易可以自己看看,如果了解汇编代码(KiUserApcDispatcher很小)

+0

这是绝对正确的,但我认为Hans也是对的:如果你的代码*依赖于这种行为,你很可能做错了什么。 (可能有边缘情况。) –

+0

@HarryJohnston - 是的,同意。但我只是正式回答问题。解释APC如何工作 – RbMm