Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当GetTickCount()包装时会发生什么?_C++_C_Windows_Winapi - Fatal编程技术网

C++ 当GetTickCount()包装时会发生什么?

C++ 当GetTickCount()包装时会发生什么?,c++,c,windows,winapi,C++,C,Windows,Winapi,如果线程正在执行以下操作: const DWORD interval = 20000; DWORD ticks = GetTickCount(); while(true) { DoTasksThatTakeVariableTime(); if( GetTickCount() - ticks > interval ) { DoIntervalTasks(); ticks = GetTickCount(); } } 最后,当值

如果线程正在执行以下操作:

const DWORD interval = 20000;
DWORD ticks = GetTickCount();
while(true)
{
    DoTasksThatTakeVariableTime();

    if( GetTickCount() - ticks > interval )
    {
        DoIntervalTasks();
        ticks = GetTickCount();
    }
}
最后,当值不适合DWORD时,记号将自动换行

我一直在和一位同事讨论这个问题。我们中的一个人相信代码在进行换行时仍然会表现得“很好”,因为减法操作也会进行换行。我们中的另一个人认为它不会一直起作用,特别是当间隔时间很长的时候

谁是对的,为什么

谢谢。

发件人:

经过的时间存储为DWORD 价值因此,时间将结束 如果系统运行,大约为零 连续49.7天。避 要解决此问题,请使用GetTickCount64。 否则,请检查溢出 比较时间时的条件

但是,德沃德没有签名,所以你应该没事。0-“非常大的数字”=“小的数字”(当然,假设您没有任何溢出检查处于活动状态)。我之前的编辑建议你得到一个负数,但那是在我考虑到DWORD没有签名之前

但是,如果手术只需要不到49.7天,你仍然会遇到问题。这可能不是您的问题;)


测试的一种方法是去掉
GetTickCount()
方法,这样您就可以在显式包装的地方编写单元测试。再说一次,如果你真的只是怀疑算术部分,你可以很容易地为此编写单元测试:)真的,只要你知道系统时钟包装时的行为,那么这个数字来自系统时钟的事实几乎是无关紧要的——这在文档中有详细说明。

我最近遇到了这个问题。我正在处理的代码在很多地方使用了GetTickCount(),以确定程序是否在某个特定任务上花费了太多时间,如果是这样,它将暂停该任务,并重新安排它以供以后执行。如果GetTickCount()在一个度量周期内被包装,就会导致代码过早超时。这是一项持续运行的服务,因此每49天就会有一次轻微的打嗝


我通过编写一个计时器类修复了它,该类在内部使用了GetTickCount(),但在值包装和补偿时检测到了它。

您肯定需要处理这个勾号包装问题

Linux内核使用以下技巧处理此类记号换行问题:

#在(a,b)之后定义时间(长)(b)-(长)(a)<0))

该思想被强制转换为无符号,以对其进行签名并比较其值,然后仅当| a-b |可以测试它时;)-我这里有一个简单的测试应用程序,它将启动一个应用程序,并在其中钩住
GetTickCount()
,以便您可以从测试应用程序的GUI控制它。我写这篇文章是因为在某些应用程序中清除
GetTickCount()
调用并不是那么容易

TickShifter是免费的,可在以下位置获得:

我是在写一系列关于测试驱动开发的文章时写这篇文章的,这些文章使用了一些断章取义地使用
GetTickCount()
的代码

如果您感兴趣,可以在此处找到文章:


但是,总而言之,您的代码将正常工作…

如果您想测试当
GetTickCount()
包装时会发生什么,您可以启用应用程序验证程序的时间滚动测试

发件人:

TimeRollOver强制GetTickCount和TimeGetTime API以比通常更快的速度滚动。这使得应用程序能够更轻松地测试其对时间翻转的处理


我建议计算两个刻度之间的实际运行时间,而不是依赖编译器来为您处理:

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();
    }
}

这篇文章帮助了我,但我认为其中存在一个缺陷:

#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)

只要:

  • 您可以减去DWORD,而不是先转换为其他类型

  • 没有任何东西需要超过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
,这意味着操作大约需要5秒钟

现在考虑一个花费很短时间的操作,但是<代码> GETICKCOUNTUCT/CONT>绕了一圈:

t1 = 4294967173
t2 = 1111
该操作耗时1234ms,但计时器已关闭,
1111-4294967173
-4294966062
的伪值。我们到底要做什么

好的,模232,减法的结果也环绕着:

(DWORD)-4294966062 == (DWORD)1234

最后,考虑一个操作需要近232毫秒但不完全的边缘情况:

t1 = 2339189280
t2 = 2339167207
在这里,
GetTickCount
绕了一圈,回到了原来的位置

现在,
t2-t1
产生的伪值为
42945223
。那是因为这是手术实际花费的时间

一般而言:

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

我知道这与11年后的Vista中的GetTickCount64()完全无关,但这里有一点帮助代码,我从永远以来都在我的tookit中使用,这是我以前使用过的

inline DWORD GetElapsed(DWORD from, DWORD to = ::GetTickCount())
{
  if (from < to)        //check for wrap around condition
      return (to - from);
  else
      return ((0xFFFFFFFFL - from) + 1 + to);
}
担心的不是你的手术可能需要比49.7天更长的时间,而是滴答声
inline DWORD GetElapsed(DWORD from, DWORD to = ::GetTickCount())
{
  if (from < to)        //check for wrap around condition
      return (to - from);
  else
      return ((0xFFFFFFFFL - from) + 1 + to);
}
DWORD start = ::GetTickCount();

// Some time later

DWORD elapsed = GetElapsed(start);