我假设 StartTime 是一个正符号整数;我假设您之前做过 StartTime = (Environment.TickCount And Int32.MaxValue)。
Abs()
不能解决问题。如果 Interval < 12.43 天,则代码将正确计时,而 StartTime 较小。但有时,每当 StartTime > (24.86 days - Interval) 时,测试将比应有的更早通过,即 (TickCount And Int32.MaxValue) 翻转为 0 的那一刻。此外,如果 Interval > 12.43 天 AND (TickCount并且 Int32.MaxValue) 接近 12.43 天,测试永远不会通过。
做Environment.TickCount And Int32.MaxValue
没有必要,也没有帮助。它生成一个正符号整数 32,表示以毫秒为单位的时间,每 24.86 天环绕到 0。替代方案更难理解,但它们可以让您毫无困难地进行长达 49.71 天的时间间隔。原始Environment.TickCount
数据在 24.86 天后和每 49.71 天后环绕到 Int32.MinValue。强制转换unchecked((Uint32)Environment.TickCount)
生成一个 [正] 无符号整数 32,表示以毫秒为单位的时间,每 49.71 天回绕到 0。(因为Environment.TickCount
调用了 Windows 函数 GetTickCount(),它返回一个 DWORD (UInt32),并将其未经检查地强制转换为 Int32。)
的环绕Environment.TickCount
不会影响经过时间的测量。未经检查的减法总是给出正确的结果。
您可以将经过时间计算为带符号的 int32(-24.86 到 +24.86 天),如果您比较独立时间或可能混合未来和过去,则更有用;或 unsigned int32(0 到 +49.71 天)。您可以将 T0 捕获为有符号 int32 或无符号 int32;它对结果没有影响。如果 T0 或经过的时间未签名,则只需要 [unchecked] 强制转换;带有签名的 T0 和签名的经过时间,您不需要演员表。
捕获已签名的 T0:(C#)
...
int iT0 = Environment.TickCount; // T0 is NOW.
...
iElapsed = unchecked(Environment.TickCount - iT0) // -24.81 to +24.81 days
uiElapsed = unchecked((uint)Environment.TickCount - (uint)iT0) // 0 to +49.71 days
if (uiElapsed >= uiTimeLimit) // IF time expired,
{
iT0 = Environment.TickCount; // For the next interval, new T0 is NOW.
...
}
捕获未签名的 T0(我的偏好;Environment.TickCount
不应该被签名):
...
uint uiT0 = unchecked((uint)Environment.TickCount); // T0 is NOW.
...
iElapsed = unchecked(Environment.TickCount - (int)uiT0) // -24.81 to +24.81 days
uiElapsed = unchecked((uint)Environment.TickCount - uiT0) // 0 to +49.71 days
if (uiElapsed >= uiTimeLimit) // IF time expired,
{
uiT0 = unchecked((uint)Environment.TickCount); // For the next interval, new T0 is NOW.
...
}
如果您的 TimeLimit 接近环绕限制(24.81 或 49.71 天),则时间可能会在未通过测试的情况下到期。您必须在 Elapsed >= TimeLimit 时至少测试一次。(如果您不确定测试的频率是否足够高,您可以在 Elapsed 上添加一个备份测试。如果 Elapsed 减少,它已经结束,所以时间必须到了。)
=====
对于超过 49.71 天的时间间隔,您可以计算 uiElapsed 回绕的次数,也可以计算Environment.TickCount
回绕的次数。您可以将计数器组合成一个 64 位值,进行模拟GetTickCount64()
(仅在 Windows Vista 和更新版本中可用)。64 位值具有全范围(2.92 亿年)和全分辨率(1 毫秒)。或者,您可以制作一个 32 位值,其范围和/或分辨率有所降低。检查换行的代码必须至少每 49.71 天执行一次,以确保未检测到换行。
uint uiTickCountPrev = 0;
uint uiTickWrap = 0;
Int64 TickCount64;
...
uiTickCount = unchecked((uint)Environment.TickCount) // 0 to +49.71 days
if (uiTickCount < uiTickCountPrev) // IF uiElapsed decreased,
uiWrapcount++; count that uiElapsed wrapped.
uiElapsedPrev = uiElapsed; // Save the previous value.
TickCount64 = (Int64)uiTickWrap << 32 + (Int64)uiTickCount;
笔记:
Environment.TickCount
给出自启动以来的时间,以毫秒为单位,分辨率为 10-16 毫秒。
未经检查的Int32差异给出了时间差,-24.81 到 +24.81 天,带有环绕。未经检查的 32 位整数减法溢出并回绕到正确的值。的标志Environment.TickCount
从不重要。示例,由一个环绕:iBase = Environment.TickCount
gets Int32.MaxValue
; 一个滴答声后,Environment.TickCount
换行到Int32.MinValue
; 并unchecked(Environment.TickCount - iBase)
产生 1。
未经检查的UInt32差异给出了时间差,0 到 +49.71 天,带有环绕。(经过的时间永远不会是负数,因此这是更好的选择。)无符号 32 位整数的未经检查的减法溢出并回绕到正确的值。示例,由一个环绕:iBase = Environment.TickCount
gets UInt32.MaxValue
; 一个滴答声后,Environment.TickCount
换行到UInt32.MinValue
; 并unchecked(Environment.TickCount - iBase)
产生 1。