为何时间测量偶尔返回15.625ms倍数的重复值?如何消除?
解决C++ Sleep计时出现15.625ms重复值的问题
这个问题我太熟悉了——本质上是Windows系统定时器默认分辨率限制导致的,咱们一步步拆解:
为什么会出现15.625ms的重复值?
Windows传统系统定时器的默认分辨率是15.625ms(对应64Hz的系统时钟滴答)。Sleep()函数的精度完全依赖这个系统时钟:当你调用Sleep(1)时,系统并不会真的等1ms,而是会等到下一个时钟滴答触发,所以实际等待时间会被"对齐"到15.625ms的整数倍。这就导致你的小数值等待(比如1-15ms)都会返回接近15.625ms的结果,看起来像是重复值。
而且你提到减少后台进程没用,因为这个是系统级的定时器设置,和进程负载关系不大。
怎么解决这个问题?
1. 临时提升系统定时器分辨率
Windows提供了timeBeginPeriod()和timeEndPeriod()函数(需要链接winmm.lib),可以临时把系统定时器分辨率提升到1ms,这样Sleep()的精度就能大幅提升,避免出现固定倍数的偏差。
修改后的代码示例:
#include <iostream> #include <chrono> #include <windows.h> #include <mmsystem.h> // 引入timeBeginPeriod相关声明 #pragma comment(lib, "winmm.lib") // 编译时链接winmm库 void stall(int milliseconds){ auto start = std::chrono::high_resolution_clock::now(); Sleep(milliseconds); auto finish = std::chrono::high_resolution_clock::now(); std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start).count()/1000000.0 << " ms\n"; } int main(){ timeBeginPeriod(1); // 将系统定时器分辨率设为1ms std::cout << "Begin\n"; for (int i = 1; i < 100; i++){ stall(i); } timeEndPeriod(1); // 用完务必恢复默认分辨率,避免增加系统功耗 return 0; }
2. 用高精度等待替代Sleep
如果你不想修改系统全局的定时器设置,也可以用std::this_thread::sleep_for(需要包含<thread>头文件),它在Windows下内部会优先尝试使用高精度定时器,配合上面的分辨率提升效果会更好:
#include <thread> // ... std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
注意事项
timeBeginPeriod会影响整个系统的时钟频率,用完一定要用timeEndPeriod恢复默认值,否则会让系统保持高频时钟滴答,增加不必要的功耗。- 即使提升了分辨率,也不能保证等待时间100%精准(系统调度可能有微小延迟),但完全可以解决你遇到的重复值问题。
内容的提问来源于stack exchange,提问作者Daniel Franklin
相关产品推荐
相关产品推荐

