默认情况下,创建线程时不会创建这个APC队列
调用了QueueUserAPC函数或其他可向APC队列添加函数之后,才会创建APC这个队列;
每个线程都有自己的APC队列 , 当线程处在alertable状态时才去执行这些APC函数.
alertable : 当线程调用例如: WaitForSingleObjectEx , SleepEx 等带ex 的函数, 并把bAlterable参数设置TRUE;
只有当APC队列中的所有函数都被执行完毕后,线程函数才会被唤醒来继续执行, 按fifo调用顺序;
第一个例子:
void __stdcall apc_func(
ULONG_PTR dwParam
)
{
printf("%d is running\n", dwParam);
Sleep(500);
}
// QueueUserAPC把一个apc函数添加到指定线程的apc队列
void test_apc(){
for (int i = 0; i < 10; ++i)
QueueUserAPC(apc_func, GetCurrentThread(), i);
SleepEx(-1, TRUE); // Alterable , 如果FALSE则不执行
printf("end\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
_tsetlocale(LC_CTYPE, TEXT(""));
test_apc();
return 0;
}
第2个例子: 注意 Wait....ex 这类函数的返回值;
void __stdcall apc_func2(
ULONG_PTR dwParam
)
{
_tprintf(TEXT("apc_func tid:%d\n"), GetCurrentThreadId());
Sleep(500);
}
unsigned int __stdcall tproc(void *param)
{
//添加 apc 函数,
for (int i = 0; i < 5; ++i)
QueueUserAPC(apc_func2, GetCurrentThread(), i);
_tprintf(TEXT("线程开始 tid:%d\n"),GetCurrentThreadId());
HANDLE e = (HANDLE)param;
//注意参数, 只有当所有apc执行完后才返回,返回值与SetEvent 不一样
DWORD ret = WaitForSingleObjectEx(e, -1, TRUE);
switch (ret)
{
case WAIT_OBJECT_0: _tprintf(TEXT("事件触发!\n")); break;
case WAIT_IO_COMPLETION:_tprintf(TEXT("APC队列执行完了!\n")); break;
case WAIT_FAILED:_tprintf(TEXT("WaitForSingleObjectEx 失败\n")); break;
}
_tprintf(TEXT("end\n"));
return 0;
}
void test_apc2()
{
//一个事件
HANDLE e = CreateEvent(NULL, TRUE,FALSE,NULL);
HANDLE t = (HANDLE)_beginthreadex(0, 0, tproc, (void*)e, 0,NULL);
WaitForSingleObject(t, -1);
}
int _tmain(int argc, _TCHAR* argv[])
{
_tsetlocale(LC_CTYPE, TEXT(""));
test_apc2();
return 0;
}