Windows NT 系列(NT 4.0/2000/XP)的系統時間更新頻率受限於時鐘中斷週期(單核 10ms、多核 15ms),GetSystemTime 回傳的毫秒欄位實際精度僅止於此。但許多場景(線程同步、高頻事件排序、效能分析)需要亞毫秒甚至微秒級的時間戳。本文深入剖析性能計數器融合系統時間的方案,揭示其固有缺陷,並給出一套工業級可用的 time_provider 解決方案。
實測 GetSystemTimeAsFileTime 連續呼叫輸出:
20:12:23.479
20:12:23.479
20:12:23.494 ← 跳躍 15ms
20:12:23.494
...
根因:Windows 只在每個時鐘中斷(Clock Interrupt)更新系統時間,調度器也在同一週期觸發。單靠系統 API 無法突破此物理限制。
常見做法:QueryPerformanceCounter (QPC) 提供高頻硬體計數器,配合 QueryPerformanceFrequency (QPF) 換算時間。同步邏輯如下:
CurrentTime = BaseSysTime + (QPC_Now - BaseQPC) / Frequency。實測確能產出微秒級時間流:
21:23:22.296
21:23:22.297
21:23:22.298
...
但存在三大致命缺陷:
SetSystemTimeAdjustment 微調時鐘頻率,均會導致高精度時間瞬間失準。prev_diff 變量記錄連續兩次 QPC 差值,推算系統時間變化發生的可能區間。
WM_TIMECHANGE 訊息立即觸發重同步。GetSystemTimeAdjustment 讀取當前調整值。template<
typename counter_type,
int KEEP_WITHIN_MICROS = 100, // 最大允許偏差(μs)
int SYNCHRONIZE_THREAD_PRIORITY = THREAD_PRIORITY_BELOW_NORMAL,
int TUNING_LIMIT_PARTSPERBILLION = 100, // 頻率修正上限(ppb)
int MAX_WAIT_MILLIS = 10000,
int MIN_WAIT_MILLIS = 100
>
class time_provider;
使用方式極簡:
typedef hrt::time_provider<hrt::performance_counter> time_provider_t;
time_provider_t& provider = time_provider_t::instance();
SYSTEMTIME st;
provider.systemtime(&st); // 獲取高精度系統時間
表 9 對比 GetSystemTime 耗時百分比(雙核 SMP / 單核):
time_provider (QPC) 系統時間轉換:~300% / ~500%提供實驗性 tsc_counter 直接讀取 Pentium TSC,效能大幅優於 QPC(系統時間轉換僅 133%、原始讀取 5.9%)。
附件含完整原始碼(VC++ 7.1 / XP 測試)、多線程範例與
tsc_counter實驗實作。