1. 程式人生 > >用戶層APC隊列使用

用戶層APC隊列使用

對象 添加 UNC winapi 核心 使用 value 是否 turn

一 參考

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 }

用戶層APC隊列使用