代码之家  ›  专栏  ›  技术社区  ›  Tim Ring

win32 api计时器

  •  2
  • Tim Ring  · 技术社区  · 16 年前

    我使用系统计时器(clock()函数,请参阅time.h)来计时一些串行和USB通信。我只需要大约1毫秒的Accurace。我注意到的第一件事是,单个时间可以超过(正负)10毫秒。随着时间的推移,对一些较小的事件进行计时会导致计时不太准确。总的时机稍微好一点。在msdn等的根目录下运行了一段时间后,我偶然发现了windows多媒体库中的计时器(timegettime(),请参阅mmsystem.h)。这是更好的与体面的精度到1毫秒的水平。

    然后,奇怪的事情接踵而至,在最初的几天工作中出现了缺陷(可爱的日志和有用的计时),这一切都变成了梨形,因为这个api也开始显示这种奇怪的粒度(而不是一堆占用3ms、2ms、3ms、2ms、3ms等的小comms消息,它显示为0ms、0ms、0ms、0ms、15ms等)。重启电脑恢复了正常的Accuarce,但在某个不确定的时间(大约一小时后),Anomoly返回。

    任何人都对如何在windows xp(使用visual studio 2008的32位pro)上获得这种级别的计时精度有任何想法或建议。

    我的计时课:

    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 回复  |  直到 16 年前
        1
  •  9
  •   Jerry Coffin    16 年前

    你打过电话吗 timeBeginPeriod(1); 要将多媒体分辨率设置为1毫秒?多媒体定时器的分辨率是系统全局性的,所以如果你不是自己设置的,你很可能是在其他东西调用它之后启动的,然后当其他东西调用它时 timeEndPeriod() ,分辨率恢复到系统默认值(如果内存可用,通常为10毫秒)。

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

        2
  •  4
  •   Reed Copsey    16 年前

    如果你想在windows上实现高分辨率计时,你应该考虑使用 QueryPerformanceFrequency QueryPerformanceCounter

    这些将在windows上提供最精确的计时,并且随着时间的推移应该更加“稳定”。qpf给出每秒的计数,qpc给出当前的计数。你可以用它在大多数系统上进行非常高的分辨率计时(毫秒的分数)。

        3
  •  1
  •   Xorlev    16 年前

    查看win32 api中的高分辨率计时器。

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

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