调用CreateThreadpoolTimer前如何检查线程池是否存在?
调用
CreateThreadpoolTimer前检查线程池是否存在的解决方案 问题背景
程序在退出阶段调用CreateThreadpoolTimer时触发TppRaiseInvalidParameter错误,堆栈跟踪如下:
ntdll!TppRaiseInvalidParameter+0x48 [minkernel\threadpool\ntdll\tp.c @ 191] ntdll!TpAllocTimer+0xa616b [minkernel\threadpool\ntdll\timer.c @ 1468] kernel32!CreateThreadpoolTimerStub+0x1b [clientcore\base\win32\client\stub.c @ 5488] fabricruntime!Common::Timer::GetTimerCallerHoldingLock+0x6a [C:\__w\1\s\src\prod\src\Common\Timer.cpp @ 194] fabricruntime!Common::Timer::SetTimer+0x5e [C:\__w\1\s\src\prod\src\Common\Timer.cpp @ 79] fabricruntime!Common::Timer::Change+0x55 [C:\__w\1\s\src\prod\src\Common\Timer.cpp @ 56] fabricruntime!Common::TimedAsyncOperation::InternalStartTimer+0x197 [C:\__w\1\s\src\prod\src\Common\TimedAsyncOperation.cpp @ 58] fabricruntime!Common::AsyncOperation::Start+0xc0 [C:\__w\1\s\src\prod\src\Common\AsyncOperation.cpp @ 77] fabricruntime!Transport::RequestReply::RequestReplyAsyncOperation::OnStart+0x1a6 [C:\__w\1\s\src\prod\src\Transport\requestreply.cpp @ 78] fabricruntime!Common::AsyncOperation::Start+0xc0 [C:\__w\1\s\src\prod\src\Common\AsyncOperation.cpp @ 77] fabricruntime!Common::AsyncOperation::CreateAndStart_Transport::RequestReply::RequestReplyAsyncOperation,Transport::RequestReply &,std::unique_ptr_Transport::Message,std::default_delete_Transport::Message_ _,std::shared_ptr_Transport::ISendTarget_ const &,enum Transpor+0xc7 [C:\__w\1\s\src\prod\src\Common\AsyncOperation.h @ 188] fabricruntime!Transport::RequestReply::BeginRequest+0x3e [C:\__w\1\s\src\prod\src\Transport\requestreply.cpp @ 253] fabricruntime!Transport::TcpClient_Transport::IpcDemuxer,17_::BeginRequest+0x74 [C:\__w\1\s\src\prod\src\Transport\TcpClient.h @ 110] fabricruntime!Hosting2::ApplicationHost::UnregisterFabricRuntimeAsyncOperation::UnregisterFabricRuntime+0x1ab [C:\__w\1\s\src\prod\src\Hosting2\ApplicationHost.cpp @ 2256] fabricruntime!Common::AsyncOperation::Start+0xc0 [C:\__w\1\s\src\prod\src\Common\AsyncOperation.cpp @ 77] fabricruntime!Hosting2::ApplicationHost::UnregisterRuntimeAsync+0x102 [C:\__w\1\s\src\prod\src\Hosting2\ApplicationHost.cpp @ 3313] fabricruntime!Hosting2::ComFabricRuntime::~ComFabricRuntime+0x5a [C:\__w\1\s\src\prod\src\Hosting2\ComFabricRuntime.cpp @ 498] fabricruntime!Hosting2::ComFabricRuntime::`scalar deleting destructor'+0x14 fabricruntime!Common::ComUnknownBase::BaseRelease+0x3e [C:\__w\1\s\src\prod\src\Common\ComUnknownBase.cpp @ 69]
错误根源是程序关闭时线程池已被销毁,但仍有异步操作尝试创建线程池定时器。
解决方案
1. 提前拦截关闭流程中的定时器创建
- 添加生命周期标记:在组件或全局层面维护一个
isShuttingDown布尔标记,启动关闭流程时立即设置为true。所有调用CreateThreadpoolTimer的代码先检查该标记,若已进入关闭状态则直接跳过创建逻辑。 - 同步等待异步任务结束:在销毁线程池前,使用事件对象或等待句柄,等待所有待处理的异步操作完成,确保没有后续代码会尝试创建定时器。
2. 检查CreateThreadpoolTimer的返回值
根据Windows官方文档,CreateThreadpoolTimer创建失败时会返回NULL,可通过返回值结合错误码判断线程池状态:
PTP_TIMER timer = CreateThreadpoolTimer(TimerCallback, context, NULL); if (timer == NULL) { DWORD error = GetLastError(); // ERROR_INVALID_PARAMETER通常意味着线程池已不存在或参数无效 if (error == ERROR_INVALID_PARAMETER) { // 跳过后续依赖定时器的逻辑,直接返回 return; } // 处理其他创建失败的情况 }
3. 使用自定义线程池替代默认池
如果依赖系统默认线程池,改为创建自定义线程池,完全控制其生命周期:
- 用
CreateThreadpool创建自定义池; - 创建定时器时将自定义池传入
CreateThreadpoolTimer的第三个参数; - 在关闭流程中,先调用
WaitForThreadpoolCallbacks等待所有定时器任务完成,再调用CloseThreadpool销毁池。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

