Multimedia Timers

Multimedia Timers

 

到目前为止,所知道的精度最高的定时器就是多媒体定时器了,大多数系统应该都可以达到1ms的精度,而其他SetTimer,CreateWaitableTimer,Sleep,GetTickCount等都只能达到15,16ms。

 

因为以前对GetTickCount不了解,所以今天早上在验证timeSetEvent的时候,老是发现1ms的定时器每次取的时间都不是相差1ms,或者是相同,或者相差15,16毫秒,这次终于明白了。(用timeGetTime才可能达到1ms精度)

 

在使用多媒体定时器之前,我们必须调用timeBeginPeriod函数设置精度,如果不设置的话,多媒体定时器就和其他的定时器一样,精度在15,16ms左右,也就是说timeGetTime,timeSetEvent都不准了。

 

所有的定时器对应的回调函数都是运行在一个线程中。

 

注意,多媒体定时器是每隔多长时间触发一次,假如回调函数没把时间花完的话,很好理解,也很准!假如回调函数花的时间超过了定时器间隔的话,这次回调函数执行完之后,马上就会触发下一次。(不是之前理解的回调执行完之后再隔多长时间后才触发)

 

精度的意思就是偏离准确值的大小,比如当前时间是100,如果精度是5ms,那么返回的时间可能在95~105之间。Forexample, if you specify a resolution of 5 and an event delay of 100, the timerservices notify the callback function after an interval ranging from 95 to 105milliseconds.

 

一个简单的使用例子

#include <windows.h>

#include <stdio.h>

#include <Mmsystem.h>

#pragma comment(lib, "Winmm.lib")

 

void CALLBACK OneShotTimer(UINT wTimerID, UINT msg,

                           DWORD dwUser, DWORD dw1, DWORD dw2)

{

    FILE* pf = (FILE*)dwUser;

    char buf[256];

 

 

    sprintf_s(buf, "timeGetTime = %u\n", timeGetTime());

 

    fputs(buf, pf);

    fflush(pf);

}

 

#define TARGET_RESOLUTION 1         //1-millisecond target resolution

int main()

{

    FILE* pf = fopen("D:\\a.txt","w");

 

    TIMECAPS tc;

    UINT     wTimerRes;

 

    if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)

    {

        // Error; application can't continue.

    }

 

    wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION),tc.wPeriodMax);

    timeBeginPeriod(wTimerRes);

 

    UINT nTimerID = timeSetEvent(1,                    //delay

        wTimerRes,                     //resolution (global variable)

        OneShotTimer,                  //callback function

        (DWORD_PTR)pf,                 //user data

        TIME_PERIODIC | TIME_CALLBACK_FUNCTION);

 

    getchar();

    timeKillEvent(nTimerID);

    timeEndPeriod(wTimerRes);

 

    return 0;

}

 

没搞懂的问题:

1、当调用timeBeginPeriod设置精度后,好像timeSetEvent中的第二个参数就没效果了,我试一下,用timeBeginPeriod设置精度为1ms,在timeSetEvent中传递的精度为5ms,但是系统还是每隔1ms触发。

假如不调用timeBeginPeriod,直接调用timeSetEvent传递一个精度,此时会有效吗?因为没用调用timeBeginPeriod,导致没有取精确时间的函数来验证?

 

2.You must match each call totimeBeginPeriod with a call to timeEndPeriod, specifying the same minimumresolution in both calls. An application can make multiple timeBeginPeriodcalls, as long as each call is matched with a call to timeEndPeriod.

假如我们没有按规定做会出现什么情况?

答:例

ret = timeBeginPeriod(wTimerRes);

ret = timeEndPeriod(wTimerRes); // 你得先调用它

ret = timeBeginPeriod(5);

上面这段话的意思是,当你要设置新的精度的时候,如果之前你设置过,你得调用timeEndPeriod后再设置。否则,高精度的会覆盖掉低精度的,但低精度的不会覆盖高精度的。

设置的这个精度,实际上是一个全局的东西,一改变会影响所有东西,包括已存在的定时器。

 

注意:

一、多媒体定时器线程的优先级是15级,如果太忙,可能会造成其他线程根本得不到处理的机会。

二、timeKillEvent和回调函数是异步的,即如果回调正在执行,timeKillEvent不会等待回调执行完才返回,而是直接返回,sip呼叫器关闭时发生崩溃就是这个原因引起的。所以,在结束多媒体定时器的时候要慎重!

 

 

 

你可能感兴趣的:(Multimedia Timers)