Win32 API计时器

时间:2010-02-16 17:25:28

标签: c++ c winapi timer system

我正在使用系统定时器(clock()函数,请参阅time.h)来计算一些串行和USB通信。我需要的只有大约1毫米的准备。我注意到的第一件事是个别时间可以超出(加或减)10毫秒。随着事件的发生,对一些较小的事件进行定时导致时间不准确。总体时间略好一些。在MSDN上有点根后,我偶然发现了Windows多媒体库中的计时器(timeGetTime(),参见MMSystem.h)。在1ms的水平上,这种方法的准确性要好得多。

随后发生了奇怪的事情,经过几天完美无瑕的工作(可爱的日志和有用的时间)之后,所有这些都变成了梨形,因为这个API也开始显示这种奇怪的粒度(而不是一堆小的comms消息需要3ms,2ms,3ms,2ms它出现的时间为0ms,0ms,0ms,0ms,15ms等。重新启动PC恢复了正常的准确度,但是在一些不确定的时间(一小时左右之后),anomoly返回了。

任何人对如何在Windows XP(32位Pro,使用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;
}

3 个答案:

答案 0 :(得分:9)

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

其他人建议使用QueryPerformanceCounter()。这确实具有更高的分辨率,但您仍需要小心。根据所涉及的内核,它可以/将使用x86 RDTSC函数,该函数是指令周期的64位计数器。无论好坏,在时钟频率变化的CPU上(从笔记本电脑开始,但现在几乎无处不在),时钟计数和挂壁时间之间的关系随时钟速度而变化。如果内存服务,如果强制Windows安装时假设有多个物理处理器(而不仅仅是多个内核),那么你将获得一个内核QueryPerformanceCounter()将读取主板的1.024 MHz时钟。与CPU时钟相比,这降低了分辨率,但至少速度是恒定的(如果你只需要1 ms的分辨率,那么它应该足够了)。

答案 1 :(得分:4)

如果您想在Windows上进行高分辨率计时,则应考虑使用QueryPerformanceFrequencyQueryPerformanceCounter

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

答案 2 :(得分:1)

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

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

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