最近实际工作中有一个业务需求要求1ms精度的一个定时操作,因之前这一块领域很少接触,有些文章也对多媒体定时器有描述,我结合自己的需求写了一个简单demo,以备产品代码中使用。
// MultimediaTimersDemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
LARGE_INTEGER _performance_count1{ 0 };
LARGE_INTEGER _performance_count2{ 0 };
//多媒体定时器回调函数,作为示例,只记录一下回调时刻的性能计数器
void CALLBACK multimedia_timer_proc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
::QueryPerformanceCounter(&_performance_count2);
timeKillEvent(uTimerID);
}
//多媒体定时器测试函数
void multimedia_timer_test() {
//获取性能计数器的本机频率
LARGE_INTEGER _performance_frequency;
::QueryPerformanceFrequency(&_performance_frequency);
std::cout << "QueryPerformanceFrequency() result:" << _performance_frequency.QuadPart << std::endl;
//获取多媒体定时器精度范围
TIMECAPS tc;
memset(&tc, 0, sizeof(tc));
if (timeGetDevCaps(&tc, sizeof(tc)) != TIMERR_NOERROR) {
std::cout << "\ntimeGetDevCaps() error:" << ::GetLastError();
return;
}
std::cout << "\ntimeGetDevCaps() return:\nminimum period supported:" << tc.wPeriodMin << "\nmaximum period supported:" << tc.wPeriodMax << std::endl;
//开启高精度定时
timeBeginPeriod(tc.wPeriodMin);
//测试不同的时间间隔定时器
for (int interval = 15; interval >= 1; --interval) {
//记录开启一个定时器之前的性能计数
::QueryPerformanceCounter(&_performance_count1);
auto timerid = timeSetEvent(interval, tc.wPeriodMin, multimedia_timer_proc, NULL, TIME_ONESHOT);
//保证定时器执行完毕
Sleep(1000);
std::cout << "\ntimeSetEvent(" << interval << ") return:" << timerid << std::endl;
std::cout << "pfc_beg=" << _performance_count1.QuadPart << "\npfc_end=" << _performance_count2.QuadPart << "\nused:" << 1000000 * (_performance_count2.QuadPart - _performance_count1.QuadPart) / _performance_frequency.QuadPart << "us" << std::endl;
}
std::cout << "输入任意字符结束\n";
getchar();
timeEndPeriod(tc.wPeriodMin);
}
int main()
{
multimedia_timer_test();
}
在我的开发机上运行结果为:
QueryPerformanceFrequency() result:10000000
timeGetDevCaps() return:
minimum period supported:1
maximum period supported:1000000
timeSetEvent(15) return:16
pfc_beg=10216056849365
pfc_end=10216057006210
used:15684us
timeSetEvent(14) return:32
pfc_beg=10216066879591
pfc_end=10216067014605
used:13501us
timeSetEvent(13) return:48
pfc_beg=10216076899334
pfc_end=10216077031276
used:13194us
timeSetEvent(12) return:64
pfc_beg=10216086930899
pfc_end=10216087055221
used:12432us
timeSetEvent(11) return:80
pfc_beg=10216096960224
pfc_end=10216097070690
used:11046us
timeSetEvent(10) return:96
pfc_beg=10216106989964
pfc_end=10216107100276
used:11031us
timeSetEvent(9) return:112
pfc_beg=10216117027262
pfc_end=10216117120676
used:9341us
timeSetEvent(8) return:128
pfc_beg=10216127131879
pfc_end=10216127212020
used:8014us
timeSetEvent(7) return:144
pfc_beg=10216137174968
pfc_end=10216137245500
used:7053us
timeSetEvent(6) return:160
pfc_beg=10216147287932
pfc_end=10216147356997
used:6906us
timeSetEvent(5) return:176
pfc_beg=10216157373900
pfc_end=10216157417253
used:4335us
timeSetEvent(4) return:192
pfc_beg=10216167453586
pfc_end=10216167495426
used:4184us
timeSetEvent(3) return:208
pfc_beg=10216177537103
pfc_end=10216177574443
used:3734us
timeSetEvent(2) return:224
pfc_beg=10216187637703
pfc_end=10216187661067
used:2336us
timeSetEvent(1) return:240
pfc_beg=10216197774529
pfc_end=10216197787836
used:1330us
输入任意字符结束
可以看出精度确实可以达到1毫秒以内,每次误差在300微妙左右。