更换电脑后,Sleep()的精确度会降低吗?(C+;+;) 我有一个程序,它是在几年前在C++(MFC,Visual Studio 6)中构建的,它已经在某个Windows机器上运行了相当长的一段时间(超过5年)。电脑在一个月前被更换了(旧的那个死了),此后程序的计时行为发生了变化。我需要帮助了解原因

更换电脑后,Sleep()的精确度会降低吗?(C+;+;) 我有一个程序,它是在几年前在C++(MFC,Visual Studio 6)中构建的,它已经在某个Windows机器上运行了相当长的一段时间(超过5年)。电脑在一个月前被更换了(旧的那个死了),此后程序的计时行为发生了变化。我需要帮助了解原因,c++,windows,timer,sleep,C++,Windows,Timer,Sleep,该程序的主要功能是通过向外部卡发送开和关信号来响应击键,开和关之间有非常精确的延迟。示例程序流程: > wait for keystroke... > ! keystroke occurred > send ON message > wait 150ms > send OFF message 不同的击键有不同的等待时间,在20ms到150ms之间(取决于特定的击键,这是一个非常确定的时间)。时机非常重要。使用simpleSleep()执行等待。在旧电脑上睡眠的准确

该程序的主要功能是通过向外部卡发送开和关信号来响应击键,开和关之间有非常精确的延迟。示例程序流程:

> wait for keystroke...
> ! keystroke occurred
> send ON message
> wait 150ms
> send OFF message
不同的击键有不同的等待时间,在20ms到150ms之间(取决于特定的击键,这是一个非常确定的时间)。时机非常重要。使用simple
Sleep()
执行等待。在旧电脑上睡眠的准确度为1-2ms偏差。我可以测量计算机外部的时间(在外部卡上),因此我对睡眠时间的测量非常准确。请考虑到这台机器多年来每天执行数千次这样的睡眠-休息周期,所以我所拥有的准确数据是可靠的

由于更换了PC,正时偏差超过10毫秒

我没有安装以前的电脑,所以它可能安装了一些附加软件包。此外,我很惭愧地承认我不记得以前的电脑是Windows2000还是WindowsXP。我很确定这是XP,但不是100%(我现在无法检查…)。新的是WindowsXP

我尝试将睡眠机制改为基于计时器,但精确度没有提高


有什么能解释这种变化吗?以前的电脑上是否安装了可修复此问题的软件包?是否有解决此问题的最佳做法?

睡眠取决于系统时钟。您的新机器可能与以前的机器具有不同的定时。从:

此函数使线程 放弃剩余的时间 切片并在一段时间内变得不可命名 基于 dw毫秒。系统时钟 “滴答声”以恒定速率出现。如果 dwms小于 系统时钟的分辨率 线程的睡眠时间可能少于 指定的时间长度。如果 dwms大于1 勾选但少于两个,等待可以 在一到两个刻度之间, 等等提高数据的准确性 睡眠时间间隔,呼叫 timeGetDevCaps函数用于确定 支持的最小计时器分辨率 以及timeBeginPeriod函数 将计时器分辨率设置为其默认值 最低限度打电话时要小心 timeBeginPeriod,因为频繁的呼叫可以 严重影响系统时钟, 系统电源使用情况和调度程序。 如果您调用timeBeginPeriod,请调用它 在应用程序早期和 请务必调用timeEndPeriod 函数的最末端 应用程序

文档似乎暗示您可以尝试使其更准确,但如果我是您,我不会尝试这样做。只要用定时器

你用什么定时器来代替它?如果使用SetTimer(),则该计时器也很糟糕。

正确的解决方案是使用更高的分辨率。

您的新电脑是多核的还是旧的单核的?时序精度的差异可能是使用多线程和上下文切换。

如果您的主要关注点是精度,请考虑使用.

Sleep()
函数是一个提示,提醒调度程序不要重新调度给定线程至少x毫秒,不能保证线程将在指定的时间内完全休眠。

XP上的时间分辨率大约为10毫秒-系统基本上每10毫秒“滴答”一次。由于这个原因,睡眠并不是一个很好的精确计时方法。我很确定win2000有相同的分辨率,但如果我错了,那可能是一个原因

您可以更改该分辨率,至少可以降低到1ms-请参阅或使用该分辨率-可能还有一个注册表项(windows media player也会更改该计时器,可能只有在其运行时才会更改)

可能是旧机器上的分辨率发生了某种变化。

通常Sleep()会导致延迟约15毫秒或周期倍数约15毫秒,具体取决于睡眠值。 下面是一段伪代码,这是找到它工作原理的好方法之一:

while true do
    print(GetTickCount());
    Sleep(1);
end;

它还将表明,对于Windows XP和Vista/Win 7,这段代码的行为是不同的,正如其他人所提到的,睡眠具有粗略的准确性

我通常使用Boost::asio进行这种计时:

// Set up the io_service and deadline_timer
io_service io_
deadline_timer timer(io_service);

// Configure the wait period
timer.expires_from_now(posix_time::millisec(5));
timer.wait();
Asio为您的平台使用最有效的实现;在Windows上,我相信它使用重叠IO

如果我将时间段设置为1ms并循环“timer.”调用10000次,则持续时间通常为10005-10100ms。非常准确,跨平台代码(尽管在Linux上精度不同),并且非常容易阅读


不过,我无法解释为什么你以前的电脑如此精确;每当我使用它时,睡眠时间都是+/-10毫秒-如果电脑忙的话,情况会更糟。

我对其中的差异感兴趣……你知道什么会导致睡眠行为不同吗?我宁愿不完全使用计时器……新的确实是双核的,而旧的不是。这很有意义这会导致时间差异,但如果转移到双核会降低效率,我会感到惊讶。你是否基于任何具体信息?在C++/MFC库中是否有自旋锁实现?好时机。CPU使用率将急剧上升,可能会导致其他应用程序匮乏…但这就是10毫秒需求的寿命,它无法满足由非实时操作系统保证。@Kieveli:我只在电脑上运行这个软件,所以我可以用CPU货币支付准确性…(不过,在C++/MFC中,spinlock最简单的实现是什么?)我下载了Lucas Hale的软件,明天将在安装时试用。我会更新的,谢谢。他们