Win32 API计时器

Tim*_*ing 2 c c++ winapi system timer

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

然后发生了奇怪的事情,经过几天完美无瑕的工作(可爱的日志和有用的时间)这一切都变成了梨形,因为这个API也开始显示这种奇怪的粒度(而不是一堆小通信消息需要3ms,2ms,3ms,2ms,3ms等它出现了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;
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*fin 9

您是否打电话timeBeginPeriod(1);将多媒体分辨率设置为1毫秒?多媒体计时器的分辨率是系统全局的,所以如果你没有自己的设置,有机会,你开始别的呼吁后,那么当别的东西叫timeEndPeriod(),分辨率又回到了系统默认的(这通常是10毫秒,如果内存服务).

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