我正在實現一個計時器,並且需要它每隔50毫秒左右運行一次,並且希望分辨率爲1毫秒或更少。我通過讀這兩篇文章:Windows隊列計時器的限制
http://www.codeproject.com/Articles/1236/Timers-Tutorial
http://www.virtualdub.org/blog/pivot/entry.php?id=272
奇怪的是,他們似乎是相互矛盾的。其中一種說隊列計時器對於高分辨率是有好處的,其他職位是由Windows 7系統產生的,分辨率大約爲15ms(對我的應用來說不夠好)。
因此,我對我的系統(Win7 64bit i7-4770 CPU @ 3.4 Ghz)進行了測試。我開始在一個週期爲50ms,這是我看到的(時間以來開始在左邊,右邊執行之間的差距,全部位於MS):
150 50.00
200 50.01
250 50.00
...
450 49.93
500 50.00
550 50.03
...
2250 50.10
2300 50.01
我看到的最大誤差約爲100美元,並且平均誤差大概在30美分左右。這讓我很開心。
因此,我開始放棄期間,看看它在什麼時候變得不可靠。一旦我減少了< = 5ms,我開始看到不好的結果。
以5ms爲週期,看到有些時段每隔幾秒會在3到6ms之間跳躍並不罕見。如果我將週期縮短到1毫秒,可以看到5到10毫秒到40毫秒的週期。我認爲跳到40毫秒可能是由於我在屏幕上打印東西,我不知道。
這是我的計時器回調代碼:
VOID CALLBACK timer_execute(PVOID p_parameter,
BOOLEAN p_timer_or_wait_fired)
{
LARGE_INTEGER l_now_tick;
QueryPerformanceCounter(&l_now_tick);
double now = ((l_now_tick.QuadPart - d_start.QuadPart) * 1000000)/d_frequency.QuadPart;
double us = ((l_now_tick.QuadPart - d_last_tick.QuadPart) * 1000000)/d_frequency.QuadPart;
//printf("\n%.0f\t%.2f", now/1000.0f, ms/1000.0f);
if (us > 2000 ||
us < 100)
{
printf("\n%.2f", us/1000.0f);
}
d_last_tick = l_now_tick;
}
反正在我看來,就好像隊列計時器是非常好的工具,只要你在100Hz或更慢的執行。在我鏈接到的第二篇文章(精度爲15ms左右)中發佈的糟糕結果可能是由於CPU速度較慢或配置不同所致?
我想知道是否可以期望跨多臺機器的這種性能(所有速度都比我的機器運行64位Win7速度更快或更快)?另外,我注意到如果你的回調沒有在這段時間結束之前退出,操作系統會在那裏放置另一個線程。這可能是顯而易見的,但它在任何文檔中都不突出,並且對客戶端代碼有重大影響。
在我的具體情況下,我正在使用我的軟件運行Prepar3d飛行模擬器應用程序。我猜測P3d與定時器分辨率有關。將計時器分辨率設置爲46.875(3 * 15.625)似乎會給我執行期,無論定時器分辨率發生了什麼(除非應用程序將分辨率降低到20ms)。 – Ian 2014-11-25 15:32:42
@Ian:任何應用程序請求的最高定時器分辨率都將處於活動狀態。沒有其他應用程序可以降低分辨率。因此,不能保證您選擇的3 x 15.625 ms無論如何都保持不變。另一種適應可能 - 也只是暫時的 - 會有更高的分辨率。你有沒有檢查實際的分辨率?我懷疑洛克希德馬丁公司將分辨率設置爲高於46.875毫秒Prepare3D – Arno 2014-11-25 18:31:44
Arno:哎呀,我的意思是將我的事件週期設置爲46.875ms,而不是將OS定時器分辨率設置爲。然後,計時器時間過短的唯一時間是如果另一個應用程序將分辨率設置爲10毫秒或某事,這是計時器分辨率,但我會看到我們的生產PC上會發生什麼。爲了安全起見,我可能會將分辨率強制爲5ms。謝謝。 BTW:當我嘗試使用@符號@Arno時,它在保存時從註釋中消失? – Ian 2014-11-25 20:00:52