【问题标题】:Win32 API timersWin32 API 计时器
【发布时间】:2023-03-28 17:08:01
【问题描述】:

我正在使用系统计时器(clock() 函数,请参阅 time.h)对一些串行和 USB 通信进行计时。我只需要大约 1 毫秒的准确度。我注意到的第一件事是单个时间可以超出(正负)10 毫秒。随着事件的进行,对一些较小的事件进行计时会导致计时的准确性降低。总体时间稍好一些。在 MSDN 等上有点根之后,我偶然发现了 Windows 多媒体库中的计时器(timeGetTime(),参见 MMSystem.h)。这要好得多,准确度可以达到 1 毫秒。

随后发生了奇怪的事情,在最初完美无瑕地工作了几天之后(可爱的日志和有用的时间),这一切都变成了梨形,因为这个 API 也开始显示这种奇怪的粒度(而不是一堆小的通信消息需要 3 毫秒、2 毫秒、3 毫秒、2 毫秒, 3ms 等。它以 0ms、0ms、0ms、0ms、15ms 等出现。重新启动 PC 恢复正常精度,但在某个不确定的时间(大约一个小时后)异常返回。

任何人对如何在 Windows XP(32 位专业版,使用 Visual Studio 2008)上获得这种级别的计时精度有任何想法或建议。

我的小计时课:

class TMMTimer
{
public:
    TMMTimer( unsigned long msec);
    TMMTimer();

    void Clear() { is_set = false; }
    void Set( unsigned long msec=0);

    bool Expired();
    unsigned long Elapsed();

private:
    unsigned long when;
    int roll_over;
    bool is_set;
};



/** Main constructor.
 */
TMMTimer::TMMTimer()
{
    is_set = false;
}




/** Main constructor.
 */
TMMTimer::TMMTimer( unsigned long msec)
{
    Set( msec);
}




/** Set the timer.
 *
 * @note   This sets the timer to some point in the future.
 *         Because the timer can wrap around the function sets a
 *         rollover flag for this condition which is checked by the
 *         Expired member function.
 */
void TMMTimer::Set( unsigned long msec /*=0*/)
{
    unsigned long now = timeGetTime();       // System millisecond counter.

    when = now + msec;

    if (when < now)
        roll_over = 1;
    else
        roll_over = 0;

    is_set = true;
}




/** Check if timer expired.
 *
 * @return  Returns true if expired, else false.
 *
 * @note    Also returns true if timer was never set. Note that this
 *          function can handle the situation when the system timer
 *          rolls over (approx every 47.9 days).
 */
bool TMMTimer::Expired()
{
    if (!is_set)
        return true;

    unsigned long now = timeGetTime();       // System millisecond counter.

    if (now > when)
    {
        if (!roll_over)
        {
            is_set = false;
            return true;
        }
    }
    else
    {
        if (roll_over)
            roll_over = false;
    }

    return false;
}




/** Returns time elapsed since timer expired.
 *
 * @return  Time in milliseconds, 0 if timer was never set.
 */
unsigned long TMMTimer::Elapsed()
{
    if (!is_set)
        return 0;

    return timeGetTime()-when;
}

【问题讨论】:

  • 谢谢大家,这似乎是我需要的。

标签: c++ c winapi timer system


【解决方案1】:

您是否致电timeBeginPeriod(1); 将多媒体分辨率设置为 1 毫秒?多媒体定时器的分辨率是系统全局的,所以如果你没有自己设置,很可能你是在其他人调用它之后开始的,然后当其他人调用timeEndPeriod()时,分辨率又回到系统默认值(如果没有记错,通常是 10 毫秒)。

其他人建议使用QueryPerformanceCounter()。这确实具有更高的分辨率,但您仍然需要小心。根据所涉及的内核,它可以/将使用 x86 RDTSC 功能,这是一个 64 位指令周期计数器。无论好坏,在时钟频率变化的 CPU 上(从笔记本电脑开始,但现在几乎在所有地方都很常见),时钟计数和挂时间之间的关系随着时钟速度而变化。如果内存可用,如果您在假设有多个物理处理器(而不仅仅是多个内核)的情况下强制安装 Windows,您将获得一个内核,其中QueryPerformanceCounter() 将改为读取主板的 1.024 MHz 时钟。与 CPU 时钟相比,这会降低分辨率,但至少速度是恒定的(如果您只需要 1 毫秒的分辨率,无论如何它应该绰绰有余)。

【讨论】:

【解决方案2】:

如果您想在 Windows 上获得高分辨率计时,您应该考虑使用 QueryPerformanceFrequencyQueryPerformanceCounter

这些将提供 Windows 上可用的最准确的计时,并且随着时间的推移应该更加“稳定”。 QPF 为您提供每秒计数,QPC 为您提供当前计数。您可以使用它在大多数系统上进行非常高分辨率的计时(毫秒的一部分)。

【讨论】:

    【解决方案3】:

    查看来自 Win32 API 的高分辨率计时器。

    http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx

    您通常可以使用它来获得微秒级分辨率的计时器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2012-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-22
      • 1970-01-01
      相关资源
      最近更新 更多