You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SetThreadpoolTimerEx返回FALSE却未触发回调的罕见问题求助

罕见问题:SetThreadpoolTimerEx未按预期调用回调函数

环境信息

  • 操作系统:Windows 10 22H2(版本19045.5131)
  • Visual Studio:2022(版本17.12.0)
  • SDK与工具集:Windows SDK 10.0.19041.0,Platform Toolset v143

问题详情

根据SetThreadpoolTimerEx的官方文档说明:

若定时器先前状态为“已设置”且函数返回FALSE,则回调正在执行或即将启动。

但在实际场景中,该函数返回FALSE,回调却未被调用,导致程序因等待回调信号完成而挂起。

复现用C++代码

#include <iostream>
#include <atomic>
#include <chrono>
#include <Windows.h>

std::atomic<bool> callbackDone = false;

VOID(NTAPI callback)(
    _Inout_     PTP_CALLBACK_INSTANCE Instance,
    _Inout_opt_ PVOID                 Context,
    _Inout_     PTP_TIMER             Timer
    )
{
    printf("callback...\n");
    callbackDone = true;
}

int main() {
    bool canFail = false;

    while (true) {
        callbackDone = false;
        auto timer = CreateThreadpoolTimer(callback, nullptr, nullptr);

        LARGE_INTEGER relativeTime = {};

        relativeTime.QuadPart = 10000000 * -1;

        FILETIME relativeTimeFt = {};

        relativeTimeFt.dwLowDateTime = relativeTime.LowPart;
        relativeTimeFt.dwHighDateTime = static_cast<DWORD>(relativeTime.HighPart);

        auto setRes1 = SetThreadpoolTimerEx(timer, &relativeTimeFt, 0, 0);

        Sleep(999);

        auto setRes2 = SetThreadpoolTimerEx(timer, nullptr, 0, 0);

        if (setRes2 == TRUE) {
            FILETIME now = {};
            SetThreadpoolTimerEx(timer, &now, 0, 0);
        }
        else {
            if (!callbackDone) {
                WaitForThreadpoolTimerCallbacks(timer, FALSE);
                canFail = true;
            }
        }

        if (canFail) {
            printf("waiting for possibly failed timer\n");
        }

        auto startWaitTime = std::chrono::high_resolution_clock::now();
        auto waitMsgStep = std::chrono::seconds(10);
        auto nextMsgTime = waitMsgStep;
        while (!callbackDone) {
            SleepEx(10, TRUE);

            auto waitDuration = std::chrono::duration_cast<std::chrono::seconds>(
                std::chrono::high_resolution_clock::now() - startWaitTime
            );

            if (waitDuration > nextMsgTime) {
                printf("waiting for callback to finish for %d seconds...\n", static_cast<DWORD>(nextMsgTime.count()));
                nextMsgTime += waitMsgStep;
            }
        }

        if (canFail) {
            canFail = false;
            printf("timer is ok\n");
        }

        CloseThreadpoolTimer(timer);
    }
}

可能的输出

输出截图

核心问题

即便SetThreadpoolTimerEx返回FALSE(按文档说明回调应正在执行或即将启动),但在部分罕见场景下回调从未被调用,导致程序无限挂起在等待callbackDone变为true的循环中。

疑问

  1. SetThreadpoolTimerEx是否存在已知问题:返回FALSE但回调未被触发?
  2. 是否因误用线程池定时器API导致该行为?
  3. 如何修改代码确保回调总能被触发,或正确处理未触发的情况?

补充信息

来自Raymond Chen博客的说明:

最后一种情况很有意思:当你取消定时器或等待对象时,线程池会尝试撤回所有待处理的回调,但有时回调已执行到无法撤回的阶段(比如已在执行中),此时Set...Ex函数会返回FALSE,提示你操作尚未完成,需等待回调执行完毕。

但在实际场景中,SetThreadpoolTimerEx返回FALSE后,等待了10秒甚至更久,回调仍未触发。


内容的提问来源于stack exchange,提问作者user2440195

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 18:09:50