使用带名称与回调的高分辨率可等待定时器:Bug还是特性?
Windows高分辨率可等待定时器的名称与完成例程限制
这是Windows系统的已知特性,微软官方文档确实未明确标注这些限制,但高分辨率可等待定时器存在以下两个关键约束:
核心限制说明
- 高分辨率可等待定时器不支持命名:无法通过
CreateWaitableTimerExW同时指定定时器名称和CREATE_WAITABLE_TIMER_HIGH_RESOLUTION标志,否则会返回错误码0x57(参数错误)。这是因为命名定时器设计用于跨进程共享,而高分辨率定时器依赖硬件级别的高精度调度机制,无法支持跨进程场景。 - 高分辨率可等待定时器不支持完成例程(回调):即使创建了无名称的高分辨率定时器,调用
SetWaitableTimerEx或SetWaitableTimer传入完成例程参数也会返回0x57错误。高分辨率定时器的实现逻辑与普通可等待定时器不同,仅支持同步等待模式,无法触发异步回调。
对应问题分析
- 指定名称+高分辨率标志创建失败:完全符合上述第一个限制,参数组合非法,系统直接拒绝创建。
- 无名称高分辨率定时器无法设置完成例程:符合第二个限制,高分辨率定时器不支持异步回调机制,只能通过同步等待(如
WaitForSingleObject)处理定时事件。 - 普通定时器操作正常:普通可等待定时器基于系统常规定时器队列,支持命名共享和完成例程,因此所有操作无异常。
解决方案建议
- 如果必须使用高分辨率定时:只能创建无名称的高分辨率定时器,通过同步等待方式处理触发逻辑,放弃完成例程。
- 如果需要完成例程或跨进程共享的命名定时器:只能放弃
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION标志,使用普通可等待定时器。
可复现代码
#include <iostream> #include <windows.h> #include <tchar.h> void TimerRoutine(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue) { HANDLE* hEvent = static_cast<HANDLE*>(lpArgToCompletionRoutine); if (hEvent != nullptr) { std::cout << "Test succeeded!\n"; SetEvent(*hEvent); } } int main() { constexpr int64_t COEFF{ -10'000 }; constexpr int64_t TIMEOUT{ 5'000 }; HANDLE hEvent = CreateEvent(nullptr, TRUE, FALSE, _T("AnEvent")); if (hEvent == nullptr) { DWORD err = GetLastError(); std::cerr << "Failed to create an event object, error code = " << err << std::endl; return -1; } // Create high resolution waitable timer. Uncomment one of them and compare behavior. HANDLE hTimer = CreateWaitableTimerExW(nullptr, L"ATimer", CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); // HANDLE hTimer = CreateWaitableTimerExW(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); // HANDLE hTimer = CreateWaitableTimerExW(nullptr, L"ATimer", 0, TIMER_ALL_ACCESS); if (hTimer == nullptr) { DWORD err = GetLastError(); std::cerr << "Failed to create a high resolution waitable timer with a name, error code = " << err << std::endl; CloseHandle(hEvent); return -1; } // Set timer with callback, relative timeout. LARGE_INTEGER dueTime; dueTime.QuadPart = TIMEOUT * COEFF; if (SetWaitableTimerEx(hTimer, &dueTime, 0, &TimerRoutine, &hEvent, nullptr, 0) == FALSE) { DWORD err = GetLastError(); std::cerr << "Failed to set timer, error code = " << err << std::endl; CloseHandle(hTimer); CloseHandle(hEvent); return -1; } // Wait until event object is signaled from the timer callback. WaitForSingleObjectEx(hEvent, INFINITE, TRUE); CloseHandle(hTimer); CloseHandle(hEvent); return 0; }
内容的提问来源于stack exchange,提问作者arin-berd
相关产品推荐
相关产品推荐

