Windows上的时钟漂移

16

我开发了一个能够追踪业务事件的Windows服务,它使用Windows系统时钟来为事件生成时间戳。然而,在处理器工作强度大的情况下,系统时钟可能会产生相当大的偏差,例如每分钟丢失几秒钟的情况。我们的服务器使用Windows时间服务与域控制器保持同步,该服务在幕后使用NTP进行同步,但同步频率受到域策略的控制,即使每分钟同步一次仍然会存在显着的时钟漂移。除了使用硬件时钟外,是否有其他技术可以使时钟更加稳定?


这并不是一道真正与编程有关的问题,所以我不确定它是否适合在StackOverflow上发布。 - Tim Frey
5
这似乎是一个与编程有关的问题。 - Mark
4
一个时钟每分钟的时间漂移几秒钟就是坏掉的,无论机器如何努力工作都没用。你需要新的硬件设备。 - skaffman
2
你不应该每分钟都出现几秒钟的问题。时钟可能出了问题,或者你的机器上有两个软件服务在玩弄时间并从不同的来源更改它? - hookenz
您可能正在经历微软分钟 - jww
13个回答

19
时钟滴答声应该是可预测的,但在大多数PC硬件上——因为它们不是为实时系统设计的——其他I/O设备中断优先于时钟中断,并且一些驱动程序在中断服务例程中进行广泛处理而不是将其推迟到延迟过程调用(DPC),这意味着系统可能无法服务时钟中断,直到(有时)长时间之后才会被通知。其他因素包括总线主控制器I/O控制器从CPU中窃取许多内存总线周期,导致CPU在相当长的时间内缺乏内存总线带宽。正如其他人所说,时钟生成硬件也可能随着温度变化而改变其频率。Windows确实允许调整每次中断时添加到实时时钟上的滴答声数量:请参阅SetSystemTimeAdjustment。然而,这只适用于您具有可预测的时钟偏差的情况。如果时钟只稍微偏离,SNTP客户端(“Windows时间”服务)将调整此偏差,使时钟滴答声略微快或慢以趋向于正确的时间。

13
我不知道这是否适用,但是...
Windows存在一个问题,如果你使用timeBeginPeriod()频繁改变计时器的分辨率,时钟会漂移。
实际上,Java的Thread的wait()函数(以及os::sleep()函数)在Windows上的实现中存在一个bug,导致这种行为。它总是在等待之前将计时器的分辨率设置为1毫秒,以保证准确性(无论睡眠时间多长),并在完成后立即恢复,除非其他线程仍在睡眠。这个设置/重置操作会混淆Windows时钟,因为Windows时钟期望Windows时间量子保持相对恒定。
Sun公司实际上自2006年以来就已经知道了这个问题,但是据我所知他们还没有修复它!
因为这个问题,我们的时钟实际上快了两倍!一个简单的Java程序,在一个循环中睡眠1毫秒就能展示这种行为。
解决方法是自己设置时间分辨率,将其设置为较低的值,并尽可能长时间保持不变。使用timeBeginPeriod()来控制。 (我们将其设置为1毫秒而没有任何不良影响。)
对于使用Java编码的人来说,更简单的方法是创建一个线程,在应用程序运行期间使其休眠。
请注意,这将全局修复此问题,无论哪个应用程序是实际的罪魁祸首。

哇,我每天都会遇到几个小时的延迟,而且我还要大量使用Java... - deed02392
11
当你在使用Java编程时,时间似乎会变得慢一些。就像被困在90年代一样。;-p - Macke
问题:这只适用于Java,还是Delphi或C#在频繁使用计时器时也会出现类似的问题? - Vincent
2
@Vincent:与任何调用timeBeginPeriod()并经常使用不同值的Windows应用程序相关。 - Macke

5
您可以在预定的任务.bat文件中运行"w32tm /resync"。这适用于Windows Server 2003。

4

除了更频繁地重新同步时钟外,我认为你没有太多可以做的事情,除非换一个新的主板,因为你的时钟信号似乎不在正确的频率上。


3

http://www.codinghorror.com/blog/2007/01/keeping-time-on-the-pc.html

PC的时钟通常应该在每天内精确到几秒钟。如果您的时间出现了大量的漂移,比如每天几分钟的误差,那么首先要检查的是您的交流电源。我亲自观察过一些系统,其中一个UPS插在另一个UPS上(这是不允许的),导致每天增加几分钟的误差。将不必要的UPS从链路中移除即可解决时间问题。虽然我不是硬件工程师,但我猜测主板上的实时时钟芯片可能使用了电源中的某个定时信号。


2
如前所述,Java程序可能会导致此问题。
另一种不需要修改代码的解决方案是添加VM参数-XX:+ForceTimeHighResolution(在NTP支持页面上找到)。
引用:
9.2.3. Windows和Sun的Java虚拟机
为了避免丢失中断,必须使用-XX:+ForceTimeHighResolution参数启动Sun的Java虚拟机。
有关更多信息,请参见http://www.macromedia.com/support/coldfusion/ts/documents/createuuid_clock_speed.htm
从引用链接(通过Wayback machine - 原始链接已经失效)可得知:
ColdFusion MX:CreateUUID增加Windows系统时钟速度
在Macromedia ColdFusion MX及更高版本中,在负载下多次调用createUUID函数可能会导致Windows系统时钟加速。这是Java虚拟机(JVM)的问题,在其中Thread.sleep调用小于10毫秒(ms)会导致Windows系统时钟运行更快。最初将此行为归档为Sun Java Bug 4500388(developer.java.sun.com/developer/bugParade/bugs/4500388.html),并已确认适用于1.3.x和1.4.x JVM。
在ColdFusion MX中,createUUID函数具有1毫秒的内部Thread.sleep调用。当createUUID被大量使用时,Windows系统时钟将每分钟增加几秒钟。加速率与createUUID调用次数和ColdFusion MX服务器负载成正比。Macromedia已经在Windows XP、2000和2003系统上的ColdFusion MX及更高版本中观察到了这种行为。

1

看起来你的业务很大:

拿一台旧笔记本电脑或其他不太好用的设备,但似乎有一个相对可靠的时钟,并将其称为时间管理器。时间管理器的唯一工作是每隔(比如)2分钟向服务器发送一条告知时间的消息。服务器在记录时间戳时,不使用Windows时钟,而是记录时间管理器上次信号的时间加上自信号以来经过的时间。每周检查一到两次时间管理器的时钟是否准确即可。


1

增加重新同步的频率。 如果同步是与您自己的主服务器在您自己的网络上进行的,则没有理由不每分钟同步一次。


1

更频繁地进行同步。查看{{link1:W32Time服务的注册表项}},特别关注“Period”。“SpecialSkew”听起来会有所帮助。


1

时钟漂移可能是温度的后果;也许你可以尝试让温度更加稳定 - 也许使用更好的冷却方法?但你永远无法完全消除漂移。

在分布式系统中,我们使用外部时钟(GPS接收器等...)和统计方法将CPU时间与绝对时间相关联来同步事件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接