2014-11-24 128 views
1

我正在實現一個計時器,並且需要它每隔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速度更快或更快)?另外,我注意到如果你的回調沒有在這段時間結束之前退出,操作系統會在那裏放置另一個線程。這可能是顯而易見的,但它在任何文檔中都不突出,並且對客戶端代碼有重大影響。

回答

2

Windows默認定時器分辨率爲15.625 ms。這就是你觀察到的粒度。 但是,可以按照MSDN:Obtaining and Setting Timer Resolution所述修改系統計時器分辨率。這允許在大多數平臺上將粒度減小到約1毫秒。 SO答案公開了如何獲得當前系統計時器分辨率。

甚至當平臺支持時,隱藏功能NtSetTimerResolution(...)甚至可以將定時器分辨率設置爲0.5毫秒。請參閱this SO回答「」如何將計時器分辨率設置爲0.5 ms?

...不同的配置? 這取決於底層硬件和操作系統版本。請與上述tooles計時器的分辨率。

...所有的快或快於我機器運行64bit Win7)? 是的你可以,但其他應用程序也可以設置定時器分辨率,谷歌瀏覽器是一個已知的例子,這樣的其他應用程序也可能只是暫時改變定時器的分辨率,所以你永遠不能依靠定時器分辨率 是跨平臺/時間不變的。 確保您的應用程序控制定時器分辨率爲 的唯一方法是自行將定時器粒度設置爲最小1 ms(0.5ms)。

注意:降低系統定時器粒度會導致系統中斷頻率增加。它減少了線程量(時間片)並增加了功耗。

+0

在我的具體情況下,我正在使用我的軟件運行Prepar3d飛行模擬器應用程序。我猜測P3d與定時器分辨率有關。將計時器分辨率設置爲46.875(3 * 15.625)似乎會給我執行期,無論定時器分辨率發生了什麼(除非應用程序將分辨率降低到20ms)。 – Ian 2014-11-25 15:32:42

+0

@Ian:任何應用程序請求的最高定時器分辨率都將處於活動狀態。沒有其他應用程序可以降低分辨率。因此,不能保證您選擇的3 x 15.625 ms無論如何都保持不變。另一種適應可能 - 也只是暫時的 - 會有更高的分辨率。你有沒有檢查實際的分辨率?我懷疑洛克希德馬丁公司將分辨率設置爲高於46.875毫秒Prepare3D – Arno 2014-11-25 18:31:44

+0

Arno:哎呀,我的意思是將我的事件週期設置爲46.875ms,而不是將OS定時器分辨率設置爲。然後,計時器時間過短的唯一時間是如果另一個應用程序將分辨率設置爲10毫秒或某事,這是計時器分辨率,但我會看到我們的生產PC上會發生什麼。爲了安全起見,我可能會將分辨率強制爲5ms。謝謝。 BTW:當我嘗試使用@符號@Arno時,它在保存時從註釋中消失? – Ian 2014-11-25 20:00:52

0

我相信不同之處在於系統中使用的資源管理。我剛剛在我的操作系統課程的演示中瞭解到了這一點。由於有很多進程正在運行,所以當時間太短時,可能無法足夠快地將進程排隊。另一方面,當它有更多的時間時,這個過程就會及時排隊,而且它也要優先處理。我希望這有些幫助。