SetTimer 精度不足:Windows 消息隊列機制導致最小間隔 ~10-15ms,且受 UI 線程阻塞影響CWnd::SetTimer 依賴窗口消息泵,非 GUI 類(如數據處理、網絡庫)無法直接使用| API | 用途 |
|---|---|
timeGetDevCaps | 查詢系統定時器分辨率範圍 |
timeBeginPeriod | 設置期望分辨率(如 1ms) |
timeEndPeriod | 釋放分辨率資源 |
timeSetEvent | 創建定時器,指定回調函數、週期、模式 |
timeKillEvent | 銷毀定時器 |

OnMMTimer(UINT timerID)MAP<UINT, CTimerListener*>CTimerListener,實現 OnMMTimerclass CMMTimers {
public:
// 啟動定時器
// period: 週期(ms), pListener: 回調對象, nTimerID: ID, oneShot: 單次/週期
bool startTimer(UINT period, CTimerListener* pListener = NULL, int nTimerID = 1, bool oneShot = FALSE);
// 停止指定定時器
bool stopTimer(int nTimerID);
// 停止所有定時器
void stopTimer();
// 內部回調入口(static)
static void CALLBACK internalTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
// 派生類可選重寫
virtual void timerProc(UINT nTimerID);
};
// 靜態回調函數 - 系統調用
void CALLBACK CMMTimers::internalTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
CMMTimers* pThis = (CMMTimers*)dwUser; // dwUser 傳遞 this 指針
if (pThis) pThis->timerProc(uTimerID);
}
// 實例方法 - 分發給具體監聽器
void CMMTimers::timerProc(UINT nTimerID) {
auto it = m_mapListeners.find(nTimerID);
if (it != m_mapListeners.end() && it->second) {
it->second->OnMMTimer(nTimerID);
}
}
// 啟動定時器
bool CMMTimers::startTimer(UINT period, CTimerListener* pListener, int nTimerID, bool oneShot) {
TIMECAPS tc;
timeGetDevCaps(&tc, sizeof(TIMECAPS));
period = max(period, tc.wPeriodMin); // 確保不低於系統最小分辨率
timeBeginPeriod(period);
UINT flags = oneShot ? TIME_ONESHOT : TIME_PERIODIC;
MMRESULT id = timeSetEvent(period, 0, internalTimerProc, (DWORD_PTR)this, flags);
if (id == 0) return false;
m_mapTimers[nTimerID] = id;
if (pListener) m_mapListeners[nTimerID] = pListener;
return true;
}
class CTestMMTimerDlg : public CDialog, public CTimerListener {
public:
CMMTimers m_timer;
void OnBtnStart() {
m_timer.startTimer(1, this, 1001); // 1ms 週期定時器
}
void OnBtnStop() {
m_timer.stopTimer(1001);
}
// 實現回調接口
virtual void OnMMTimer(UINT nTimerID) override {
if (nTimerID == 1001) {
// 毫秒級任務:數據采集、波形刷新、協議心跳等
UpdateWaveform();
}
}
};
| 特性 | CWnd::SetTimer | 多媒體定時器 |
|---|---|---|
| 精度 | ~10-15ms | 1ms+ (視系統而定) |
| 依賴窗口 | 是 | 否 |
| 回調線程 | UI 線程 | 系統高優先級線程 |
| UI 操作安全 | 安全 | 需 PostMessage 回 UI 線程 |
| 資源消耗 | 低 | 較高 (提高系統時鐘中斷頻率) |
timeBeginPeriod/timeEndPeriod 必須成對,否則影響系統電源管理PostMessage 或線程安全隊列傳遞給 UI 線程CreateTimerQueueTimer + SetTimerResolution;高精度場景考慮 QueryPerformanceCounter 忙等待或專用實時線程
界面顯示定時器觸發計數,驗證 1ms 週期準確性
封裝 CMMTimers 類解決了「無窗口類需要高精度定時」的痛點,結合 CTimerListener 接口實現了靈活的回調機制。雖然多媒體定時器提高了系統時鐘中斷頻率(增加功耗),但在工業控制、多媒體處理、高頻交易等場景中不可或缺。代碼結構清晰,體現了設計模式中「觀察者模式」與「適配器模式」的實踐。