Win32 QueueUserAPC函数随机报错31及执行不稳定问题求助
问题分析与修复方案
核心问题根因
1. 调度线程逻辑完全写反(导致偶发少输出、错误码31的核心原因)
你写的pure调度线程的等待逻辑完全颠倒:
原逻辑是只要WaitForSingleObjectEx返回WAIT_IO_COMPLETION(即APC投递执行完成)就直接退出线程,所以第一个APC执行完调度线程就终止了,后续所有APC投递都会发往已经退出的线程,自然就会出现thread opened输出少、第二次QueueUserAPC返回错误码31(ERROR_GEN_FAILURE,代表向已终止/不可用的线程投递APC)。
2. 事件触发时序存在竞速条件
你在唤醒工作线程的SetEvent(g_FenceEvent)执行后,立刻触发了调度线程的退出事件dispatchCloseEvent,导致部分工作线程还没来得及完成第二次QueueUserAPC投递,调度线程就已经进入退出流程,进一步拉高了错误概率。
3. 无效重复触发事件
代码末尾的SetEvent(dispatchCloseEvent)是多余操作,dispatchCloseEvent是手动重置事件,触发一次就会永久保持信号状态,不需要重复设置。
修复代码
#include <Windows.h> #include <iostream> constexpr auto fenceName = L"GlobalFence"; constexpr auto dispatchCloser = L"GlobalDispatchStop"; constexpr int threadCount = 5; DWORD WINAPI pure(LPVOID lpThreadParameter) { const HANDLE dispatchCloseEvent = OpenEventW(EVENT_ALL_ACCESS, FALSE, dispatchCloser); // 修正等待逻辑:只有等到退出事件触发才退出,APC执行完成后继续等待 while (true) { DWORD waitRet = WaitForSingleObjectEx(dispatchCloseEvent, INFINITE, TRUE); if (waitRet == WAIT_OBJECT_0) { // 收到退出信号,结束线程 break; } // WAIT_IO_COMPLETION说明APC执行完成,继续循环等待下一个事件 } CloseHandle(dispatchCloseEvent); return 0; } HANDLE dispatcher; int main() { const HANDLE dispatchCloseEvent = CreateEventW(nullptr, TRUE, FALSE, dispatchCloser); dispatcher = CreateThread(NULL, 1024, &pure, 0, 0, NULL); const HANDLE g_FenceEvent = CreateEventW(nullptr, TRUE, FALSE, fenceName); HANDLE threads[threadCount]; for (int i = 0; i < threadCount; i++) { threads[i] = CreateThread(NULL, 1024*1024, [](LPVOID) -> DWORD { DWORD d = QueueUserAPC((PAPCFUNC)[](ULONG_PTR) {std::cout << "thread opened\n"; }, dispatcher, NULL); if(d == 0)std::cout << GetLastError() << std::endl; HANDLE a = OpenEventW(EVENT_ALL_ACCESS, FALSE, fenceName); WaitForSingleObject(a, INFINITE); CloseHandle(a); d = QueueUserAPC((PAPCFUNC)[](ULONG_PTR) {std::cout << "thread released\n"; }, dispatcher, NULL); if (d == 0)std::cout << GetLastError() << std::endl; return 0; }, 0, 0, NULL); } Beep(300, 300); SetEvent(g_FenceEvent); // 先等所有工作线程完成全部APC投递,再触发调度线程退出 WaitForMultipleObjects(threadCount, threads, TRUE, INFINITE); SetEvent(dispatchCloseEvent); WaitForSingleObject(dispatcher, INFINITE); for (int i = 0; i < threadCount; i++) CloseHandle(threads[i]); CloseHandle(dispatcher); CloseHandle(g_FenceEvent); CloseHandle(dispatchCloseEvent); }
修复说明
- 修正了调度线程的等待逻辑,只有收到明确的退出信号才会终止,所有投递的APC都会被正常执行
- 调整了退出事件的触发时机:先等待所有工作线程执行完毕(完成全部APC投递),再通知调度线程退出,完全规避竞速问题
- 补充了句柄关闭操作,避免资源泄漏
- 显式将无捕获lambda转换为
PAPCFUNC类型,避免部分编译器出现类型匹配错误
内容的提问来源于stack exchange,提问作者Badasahog
相关产品推荐
相关产品推荐

