时间测量技术及其在不同平台上的应用

在软件开发中,时间测量是一个常见但复杂的问题。在Windows操作系统中,有三种主要的时间测量方法:基于系统时钟的方法、使用系统回调的等待计时器,以及使用GetTickCount和GetTickCount64函数。这些方法各有优缺点。基于系统时钟的方法可能会因为夏令时的调整或人为手动调整时钟而产生问题。使用系统回调的等待计时器虽然有效,但无法监控已经过去的时间。GetTickCount函数虽然易于使用,但每49.7天就会循环一次,而GetTickCount64函数在Windows Vista之前的版本中不可用。

在其他平台,如嵌入式系统中,由于没有实时时钟,必须通过计算由处理器或其他指定芯片引起的特定中断来进行时间测量。一些嵌入式库,如Arduino,会通过调用millis()函数来帮助完成这项工作。

在工业控制软件的开发中,经常使用基于时钟、滴答和回调的计时器。大部分工作都是使用PC来控制流程,通过从输入/输出读取信息并做出快速决策。也构建了一些嵌入式设备。

在这里提出的解决方案不应用于实时控制,除非考虑了权衡。并非所有嵌入式系统都能使用提出的方法,每个特定设备都需要单独处理。去年,有一篇文章报道了一家飞机制造商因为系统中运行的代码存在bug,需要每48天完全关闭一次。这听起来很熟悉,因为有人使用了类似于GetTickCount的调用,通过比较旧值和新值来计算各种东西。这在大多数时候都是有效的,直到32位整数填满并回滚到零,导致各种混乱。

代码实现

解决方案是将值提升到更大的64位数字。以下是使用VB.NET实现的示例代码:

Private _current As Int64 Private _last As UInt32 Declare Function GetTickCount Lib "kernel32" () As UInt32 Sub New() _current = GetTickCount() _last = _current End Sub Private Sub update() Dim t As UInt32 = GetTickCount() If t < _last Then ' 检测到回滚 Dim tmp As Int64 = t Or &H100000000 ' 32秒位 _current += (tmp - _last) Else _current += (t - _last) End If _last = t End Sub

这段代码所做的就是获取一个初始值并将其存储到一个更大的容器中,同时使用一个32位标记来记录上一次获取的值。因此,当代码更新时,获取最新的tick计数,如果它看起来比上一个值小,那么发生了回滚,所以将使用2^32位和当前值进行或运算,然后从_last值中减去这个值,以获取两次调用之间发生的时间差,并将其添加到_current标记中。

因为_current标记是64位的,确信在有生之年这个值不会回滚(重启的可能性更大)。

最终将这段代码封装到一个.NET日期样式结构中,这允许将值转换回日期或反之,以及添加或减去毫秒等。如果需要将时间戳保存到文件或日志中,总是会将其转换为日期结构,以防计算机重启。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485