gpt4 book ai didi

c++ - QueryPerformanceCounter 和溢出

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:49:17 27 4
gpt4 key购买 nike

我正在使用 QueryPerformanceCounter 在我的应用程序中做一些计时。但是,在运行几天后,该应用程序似乎停止正常运行。如果我只是重新启动应用程序,它就会再次开始工作。这让我相信我的计时代码中存在溢出问题。

// Author: Ryan M. Geiss
// http://www.geisswerks.com/ryan/FAQS/timing.html
class timer
{
public:
timer()
{
QueryPerformanceFrequency(&freq_);
QueryPerformanceCounter(&time_);
}

void tick(double interval)
{
LARGE_INTEGER t;
QueryPerformanceCounter(&t);

if (time_.QuadPart != 0)
{
int ticks_to_wait = static_cast<int>(static_cast<double>(freq_.QuadPart) * interval);
int done = 0;
do
{
QueryPerformanceCounter(&t);

int ticks_passed = static_cast<int>(static_cast<__int64>(t.QuadPart) - static_cast<__int64>(time_.QuadPart));
int ticks_left = ticks_to_wait - ticks_passed;

if (t.QuadPart < time_.QuadPart) // time wrap
done = 1;
if (ticks_passed >= ticks_to_wait)
done = 1;

if (!done)
{
// if > 0.002s left, do Sleep(1), which will actually sleep some
// steady amount, probably 1-2 ms,
// and do so in a nice way (cpu meter drops; laptop battery spared).
// otherwise, do a few Sleep(0)'s, which just give up the timeslice,
// but don't really save cpu or battery, but do pass a tiny
// amount of time.
if (ticks_left > static_cast<int>((freq_.QuadPart*2)/1000))
Sleep(1);
else
for (int i = 0; i < 10; ++i)
Sleep(0); // causes thread to give up its timeslice
}
}
while (!done);
}

time_ = t;
}
private:
LARGE_INTEGER freq_;
LARGE_INTEGER time_;
};

我的问题是上面的代码是否应该连续运行数周才能确定地工作?

如果不是,问题出在哪里?我以为溢出是由

处理的
if (t.QuadPart < time_.QuadPart)    // time wrap
done = 1;

但也许这还不够?

编辑:请注意,原始代码不是我写的,Ryan M. Geiss 写的,原始代码源的链接在代码中。

最佳答案

QueryPerformanceCounter 因其不可靠而臭名昭著。如果您准备好处理异常结果,则可以用于个别短间隔计时。它准确 - 它通常基于 PCI 总线频率,负载过重的总线会导致滴答丢失。

GetTickCount 实际上更稳定,如果您调用了 timeBeginPeriod,可以为您提供 1 毫秒的分辨率。它最终会换行,因此您需要处理它。

__rdtsc 不应使用,除非您正在分析并控制您正在运行的内核并准备好处理可变 CPU 频率。

GetSystemTime 适用于较长时间的测量,但会在调整系统时间时跳跃。

此外,Sleep(0) 并不像您认为的那样工作。 如果另一个上下文需要它它会产生 cpu - 否则它会立即返回。

简而言之,Windows 上的计时一团糟。人们会认为,今天可以从计算机上获得准确的长期计时而无需通过箍 - 但事实并非如此。在我们的游戏框架中,我们使用来自服务器的多个时间源和校正来确保所有连接的客户端具有相同的游戏时间,并且那里有很多坏时钟。

您最好的选择可能是只使用 GetTickCount 或 GetSystemTime,将其包装到可以针对时间跳跃/环绕进行调整的内容中。

此外,您应该将 double interval 转换为 int64 milliseconds,然后仅使用整数数学 - 这样可以避免由于浮点类型的精度因它们而异而导致的问题内容。

关于c++ - QueryPerformanceCounter 和溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5296990/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com