我开发了一个跟踪商业活动的Windows服务.它使用Windows时钟为事件添加时间戳.但是,基础时钟可能会非常显着地漂移(例如,每分钟丢失几秒),尤其是在CPU工作困难时.我们的服务器使用Windows时间服务与域控制器保持同步,域控制器使用NTP,但同步频率由域策略控制,无论如何甚至每分钟同步仍然会带来显着的漂移.除了使用硬件时钟之外,还有什么技术可以让时钟更稳定吗?
时钟滴答应该是可预测的,但在大多数PC硬件上 - 因为它们不是为实时系统设计的 - 其他I/O设备中断优先于时钟滴答中断,并且一些驱动程序在中断服务程序中进行大量处理而不是而不是将其推迟到延迟过程调用(DPC),这意味着系统可能无法在发出信号后很长时间(有时)提供时钟滴答中断.
其他因素包括总线主控I/O控制器,这些控制器从CPU窃取了许多存储器总线周期,导致它在很长一段时间内缺乏存储器总线带宽.
正如其他人所说,时钟生成硬件也可以随着元件值随温度变化而改变其频率.
Windows确实允许在每个中断上添加到实时时钟的滴答数量:请参阅SetSystemTimeAdjustment.但是,只有当您有可预测的时钟偏差时,这才有效.如果时钟稍微关闭,SNTP客户端("Windows时间"服务)将调整此偏斜,使时钟略微更快或更慢,以趋向正确的时间.
我不知道这是否适用,但......
Windows有一个问题,如果你用timeBeginPeriod()改变计时器分辨率很多,那么时钟就会漂移.
实际上,Java的Thread wait()
(和os::sleep()
)函数的Windows实现中存在一个导致此行为的错误.它始终在等待之前将定时器分辨率设置为1 ms以便准确(无论睡眠长度如何),并在完成后立即恢复它,除非任何其他线程仍处于休眠状态.然后,这个设置/重置将混淆Windows时钟,它希望窗口时间量相当恒定.
自2006年以来,Sun实际上已经知道了这一点,并且还没有修复它,AFAICT!
实际上我们的时钟速度是这个的两倍!一个在循环中睡眠1毫秒的简单Java程序显示了这种行为.
解决方案是将自己的时间分辨率设置为低,并尽可能长时间保持在那里.使用timeBeginPeriod()来控制它.(我们将其设置为1毫秒,没有任何不利影响.)
对于那些使用Java编码的人来说,解决这个问题的更简单方法是创建一个只要应用程序存在就会休眠的线程.
请注意,这将在全局机器上解决此问题,无论哪个应用程序是实际的罪魁祸首.
您可以在计划任务.bat文件中运行"w32tm/resync".这适用于Windows Server 2003.