导航

用户层APC队列使用

Posted on 2019-01-18 11:08  talenth  阅读(839)  评论(0编辑  收藏  举报

一 参考

https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-queueuserapc

<<windows核心编程>> 第5版

 

二 每个线程都有一个APC队列, 在线程处于可警醒状态时, 线程会执行APC队列中apc函数

  经过以上参考文章加上测试发现, APC队列中的函数会在以下3个时机调用

  1 线程已经创建, 系统在调用线程函数时会检查APC队列, 如果不为空, 则调用APC队列中的apc函数, 直到队列为空后, 才开始调用线程函数

  2 线程通过WaitForSingleObjectEx等函数进入可警醒状态时, 会先检查APC队列, 如果不为空, 则调用APC队列中的apc函数, 直到队列为空后, 才开始等待要等待的对象, 此时如果要等待的对象没有进入激发态且没有超时WaitForSingleObjectEx不会返回

  3 线程通过WaitForSingleObjectEx等函数进入可警醒状态时, APC队列为空, 且要等待的对象没有进入激发态, 也没有超时, 则线程进入睡眠等待状态, 此时往该APC队列添加APC函数后, 该线程会被唤醒执行完所有APC队列中的函数, 然后不去看要等待的对象是否进入激发态, 立即从WaitForSingleObjectEx中返回, 返回值是WAIT_IO_COMPLETION 

测试代码如下

 1 #include <windows.h>
 2 #include <iostream>
 3 #include <process.h>
 4 
 5 HANDLE hEvent = NULL;
 6 HANDLE HMainEvent = NULL;
 7 DWORD WINAPI TestProc(LPVOID lpThreadParameter)
 8 {
 9     printf("thread start\n");
10     SetEvent(HMainEvent);
11     if (hEvent && hEvent != INVALID_HANDLE_VALUE)
12     {
13         printf("waitfor start\n");
14         DWORD ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
15         //WAIT_OBJECT_0
16         printf("waitfor ret= 0x%08x\n", ret);
17     }
18     printf("thread end\n");
19     return 0;
20 }
21 VOID NTAPI TestAPC(ULONG_PTR Parameter)
22 {
23     printf("apc func start index=%u\n",Parameter);
24 }
25 int main(int argc, char **argv, char **env)
26 {
27     HANDLE hT = NULL;
28     hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
29     HMainEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
30 
31     if (hEvent)
32     {
33         hT = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)TestProc, NULL, 0, NULL);
34         if (hT && hT != INVALID_HANDLE_VALUE)
35         {
36             WaitForSingleObject(HMainEvent, INFINITE);
37             //Sleep(2000);
38             ULONG_PTR index = 1;
39             for(;index <100;++index)
40             {
41                 QueueUserAPC(TestAPC, hT, index);
42             }
43             Sleep(2000);
44             SetEvent(hEvent);
45             WaitForSingleObject(hT, INFINITE);
46         }
47     }
48     CloseHandle(hEvent);
49     CloseHandle(HMainEvent);
50     CloseHandle(hT);
51     system("pause");
52     return 0;
53 }