如何在Windows平台实现1毫秒精确延时?现有方法存16ms延迟
Windows线程睡眠1ms实际延迟16ms的问题解决
问题说明
我试过用std::this_thread::sleep_for和CreateWaitableTimer两种方式实现1ms延迟,但实际线程都会被Windows任务调度器延迟16ms左右才继续执行。只有程序处于活跃交互状态时,延迟时间才会有变化。我已经设置了SetThreadPriority优化优先级,但问题依然存在,示例代码如下:
#include <windows.h> #include <iostream> #include <thread> #include <chrono> using namespace std::chrono; using namespace std::chrono_literals; double GetTiming(); void Wait1ms(); int main() { SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ); SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); while ( true ) { //DoSomething(); Wait1ms(); // => 16ms std::this_thread::sleep_for( 1ms ); // => 16ms std::cout << "dt = " << GetTiming() << "\n"; } } void Wait1ms() { HANDLE hTimer = NULL; LARGE_INTEGER liDueTime; liDueTime.QuadPart = -10000LL; hTimer = CreateWaitableTimer(NULL, TRUE, NULL); SetWaitableTimer( hTimer, &liDueTime, 0, NULL, NULL, 0 ); auto result = ( WaitForSingleObject( hTimer, INFINITE ) != WAIT_OBJECT_0 ); } double GetTiming() { static high_resolution_clock::time_point last; const auto difference = high_resolution_clock::now() - last; last = high_resolution_clock::now(); return difference.count() / 1000000.0; }
问题根源
Windows默认系统定时器分辨率为15.625ms(约16ms),这是兼顾系统性能与兼容性的传统设置。普通睡眠、定时器API都会受这个分辨率限制——哪怕你设置1ms等待,系统也要等到下一个时钟中断触发时才会唤醒线程。
当程序处于活跃交互状态时,系统会临时提升定时器分辨率(通常到1ms),因为UI交互需要更及时的响应,所以此时延迟会缩短。
解决方法
要实现精确的1ms延迟,必须调用timeBeginPeriod和timeEndPeriod修改系统定时器分辨率,同时修正原代码中的资源泄漏问题:
修改后的代码
#include <windows.h> #include <iostream> #include <thread> #include <chrono> #include <mmsystem.h> // 包含timeBeginPeriod函数声明 #pragma comment(lib, "winmm.lib") // MSVC下链接winmm库 using namespace std::chrono; using namespace std::chrono_literals; double GetTiming(); void Wait1ms(); int main() { // 设置定时器分辨率为1ms timeBeginPeriod(1); SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ); SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); while ( true ) { //DoSomething(); Wait1ms(); // 现在实际延迟接近1ms std::this_thread::sleep_for( 1ms ); // 现在实际延迟接近1ms std::cout << "dt = " << GetTiming() << "\n"; } // 程序退出前恢复默认分辨率(实际while(true)不会走到这里,可在退出逻辑中添加) timeEndPeriod(1); } void Wait1ms() { HANDLE hTimer = NULL; LARGE_INTEGER liDueTime; liDueTime.QuadPart = -10000LL; hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if (hTimer != NULL) { SetWaitableTimer( hTimer, &liDueTime, 0, NULL, NULL, 0 ); WaitForSingleObject( hTimer, INFINITE ); CloseHandle(hTimer); // 关闭定时器句柄,避免资源泄漏 } } double GetTiming() { static high_resolution_clock::time_point last = high_resolution_clock::now(); const auto now = high_resolution_clock::now(); const auto difference = now - last; last = now; return duration_cast<microseconds>(difference).count() / 1000.0; }
关键说明
timeBeginPeriod(1):强制将系统定时器分辨率设置为1ms,让短延迟请求能被精准处理。注意程序退出时一定要调用timeEndPeriod(1)恢复默认值,否则会增加系统功耗。- 资源泄漏修正:原代码中
CreateWaitableTimer创建的句柄未关闭,修改后添加CloseHandle(hTimer)释放资源。 - 优先级设置:实时优先级类和时间关键线程优先级能确保线程在定时器触发后被立即调度,进一步提升延迟精度。
内容的提问来源于stack exchange,提问作者non-user38741
相关产品推荐
相关产品推荐

