以前對User-Mode APC不甚了解, 最近在看一個開源項目時看到了對APC的使用。看來多看代碼的確是有好處地:)廢話不多說。我們來看看APC的真面目吧。
APC即asynchronous procedure call,每一線程都有一個APC隊列。操作系統 允許一個應用向一個指定線程的APC隊列中放入APC函數。當指定的線程處於警告狀態時,該線程就會調用隊列中的APC函數。調用的順序為先入先出(FIFO)。可以用以下函數使一個線程進入警告狀態:
SleepEx, SignalObjectAndWait, WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx
一句話,就是可以讓別的線程執行一個函數。下面是一段例子

LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

if (msg==WM_NULL) SleepEx(0,TRUE);

return DefWindowProc(hwnd,msg,wParam,lParam);

}


//主線程調用

BOOL Initialize()

{

DuplicateHandle(GetCurrentProcess(),

GetCurrentThread(),

GetCurrentProcess(),

&g_hMainThread,

THREAD_SET_CONTEXT,

FALSE,

0);

//為了讓APC盡快響應,創建窗口,在WM_NULL中調用SleepEx讓線程進入警告狀態。

g_hAPCWnd = CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL);

SetWindowLongPtr(m_hACPWnd, GWL_WNDPROC, (LONG)(LONG_PTR)APCWndProc);

return TRUE;

}


//工作者線程調用

int CallFunctionAsync(void (__stdcall *func)(void *), void *arg)

{

int res = 0;

res = QueueUserAPC((void (__stdcall *)(DWORD))func, g_hMainThread, (DWord_PTR)arg);

PostMessage(g_hAPCWnd, WM_NULL, 0, 0);

return res;

}
主線程調用Initialize來創建APCWnd,以及保存主線程句柄。為了使APC能夠及時響應創建APCWnd,工作者線程調用CallFunctionAsync讓主線程運行 func函數指針指向的函數,在該函數中向APCWnd發送WM_NULL消息,窗口過程在響應該消息時調用SleepEx使線程進入警告狀態,從而檢查並調用APC隊列中的APC函數。這樣就實現了一個讓已知的線程調用指定的函數。