GetTickCount()包装时会发生什么?【JAVA教程】

!
也想出现在这里? 联系我们
信息

GetTickCount()包装时会发生什么?,第1张

概述GetTickCount()包装时会发生什么?

如果一个线程正在做这样的事情:

const DWORD interval = 20000; DWORD ticks = GetTickCount(); while(true) { DoTasksThatTakeVariableTime(); if( GetTickCount() – ticks > interval ) { DoIntervalTasks(); ticks = GetTickCount(); } }

最后,当值不适合DWORD时,将会包装刻度。

我一直在和一位同事讨论这个问题。 我们中的一个人认为,当包装发生时,代码仍然会performance得很好,因为减法 *** 作也会包装。 我们另一个人认为,这并不总是奏效,特别是如果时间间隔很大的话。

谁是对的,为什么?

“errno”声明的编译时错误

无法使用fopen()在windows 7的C驱动器中创build文件

DeBUGActiveProcess崩溃

linux不允许我访问一个固定的内存区域

什么是轻量级windows应用程序的最佳开源示例?

谢谢。

将用户在文本框中input的URL转换为URI格式

在linux中获取文件的最后修改时间

检测使用C#更改的活动窗口而不进行轮询

如何在CheckedBoxList控件中的项目上绘制string?

为什么我的dev-c ++“无法打开输出文件”?

从文档 :

所用时间以DWORD值存储。 因此,如果系统连续运行49.7天,时间将会回到零。 为了避免这个问题,使用GetTickCount64。 否则,在比较时间时检查溢出情况。

但是,DWORD是无符号的 – 所以你应该没问题。 0 – “非常大的数字”=“小数字”(假设您没有任何溢出检查活动,当然)。 我有一个以前的编辑,建议你会得到一个负数,但是之前我考虑到DWORD是无符号的。

如果 *** 作时间短于 49.7天,您仍然会遇到问题。 这对你来说可能不是问题;)

一种测试方法是将GetTickCount()方法存根出来,这样你就可以在明确地进行换行的地方编写单元测试。 然后,如果你真的只怀疑算术部分,你可以很容易地编写单元测试:)真的,这个数字来自系统时钟的事实是非常不相关的,只要你知道它的行为包装 – 这是在文档中指定的。

如果要测试GetTickCount()封装时发生的情况,可以启用Application VerifIEr的TimeRollover测试。

在软件开发周期内使用Application VerifIEr生命周期 :

TimeRollover强制GetTickCount和TimeGetTime API比平时快速翻转。 这允许应用程序更容易地测试其处理时间翻转。

没什么不好的事情发生,只要:

您减去DWORD s,而不是先转换为其他类型。

没有你想要的时间需要超过49.7天。

这是因为C语言中的无符号算术溢出是很好定义的,并且包装行为完全是我们想要的。

DWORD t1,t2; DWORD difference; t1 = GetTickCount(); DoSomethingTimeConsuming(); t2 = GetTickCount();

t2 – t1将产生正确的值,即使GetTickCount包装。 在进行减法之前,不要将t2和t1转换为其他类型(例如int或double )。

如果编程语言将溢出视为错误,这将不起作用。 如果DoSomethingTimeConsuming()花费超过49.7天,它也不会工作。 不幸的是,只能通过查看t2和t1看看GetTickCount缠绕了多少次。

让我们从通常的情况开始,在这里没有任何回旋:

t1 = 13487231 t2 = 13492843

在这里, t2 – t1 = 5612 ,这意味着 *** 作需要大约五秒钟。

现在考虑一个需要很短时间的 *** 作,但是GetTickCount包装的地方:

t1 = 4294967173 t2 = 1111

该 *** 作耗时1234ms,但定时器缠绕,而1111 – 4294967173是1111 – 4294967173的虚假值。 我们会做什么?

那么,模2 2 32 ,减法的结果也包括在内:

(DWORD)-4294966062 == (DWORD)1234

最后,考虑一个 *** 作需要接近 2 32毫秒的边界情况,但不是这样:

t1 = 2339189280 t2 = 2339167207

在这里, GetTickCount缠住了,然后回到原来的位置。

现在t2 – t1产生4294945223的虚假值。 那是因为这是 *** 作实际花费的时间!

一般来说:

(base + offset) – base ≡ offset mod 2^32

我建议计算两个滴答之间的实际流逝时间,而不是依靠编译器来为你处理:

const DWORD interval = 20000; #define TICKS_DIFF(prev,cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+1+(cur)) DWORD ticks = GetTickCount(); while(true) { DoTasksThatTakeVariableTime(); DWORD curticks = GetTickCount(); if( TICKS_DIFF(ticks,curticks) > interval ) { DoIntervalTasks(); ticks = GetTickCount(); } }

我最近遇到了这个问题。 我正在使用的代码在一堆地方使用GetTickCount()来确定程序是否花费了太多的时间在一个特定的任务,如果是的话,它会超时该任务,并重新安排它以备后用。 如果GetTickCount()在一个测量周期内被封装,将会导致代码过早超时。 这是一个不断运行的服务,每四十九天就会有一个小小的呃逆。

我通过编写一个内部使用GetTickCount()的定时器类来解决这个问题,但是当它的值被包装和补偿时,它会被检测到。

大爆炸发生。 哦,对不起,大爆炸包装。

你可以测试它;) – 我有一个简单的测试应用程序,它将启动一个应用程序并挂钩GetTickCount() ,以便您可以从测试应用程序的GUI控制它。 我把它写成了在某些应用程序中调用GetTickCount()调用并不那么容易。

TickShifter是免费的,可在这里: http : //www.lenholgate.com/blog/2006/04/tickshifter-v02.HTML

我写了一个关于测试驱动开发的系列文章,它使用了一些使用GetTickCount()代码。

如果您有兴趣,可以在这里找到相关文章: http : //www.lenholgate.com/blog/2004/05/practical-testing.HTML

但是,总之,你的代码将工作…

这篇文章帮了我,但我认为有一个错误:

#define TICKS_DIFF(prev,cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur))

当我在环绕点测试这个时,我发现它已经是1了。

对我有效的是:

define TICKS_DIFF(prev,cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur)+1)

当然,你需要处理这个刻度线问题。

linux内核使用以下技巧处理这种刻度线问题:

(a,b)((long)(b) – (long)(a)<0))#define time_after

这个想法是无符号的签名和比较它们的值,那么只有当| ab | <2 ^ 30时,这个包裹才不影响结果。

你可以尝试一下这个技巧,并了解它为什么会起作用。

由于DWORD也是无符号整数,这个技巧也应该适用于windows。

所以你的代码可能是这样的:

const DWORD interval = 20000;

DWORD ticks = GetTickCount()+ interval;

while(true){

DoTasksThatTakeVariableTime(); if(time_after(ticks,GetTickCount()) { DoIntervalTasks(); ticks = GetTickCount() + interval; }

}

只有在间隔小于0x2 ^ 30时才有效。

总结

以上是内存溢出为你收集整理的GetTickCount()包装时会发生什么?全部内容,希望文章能够帮你解决GetTickCount()包装时会发生什么?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

© 版权声明
THE END
喜欢就支持一下吧
点赞60 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容