我用一個Windows多媒體DLL來創建高分辨率定時器如何使用CreateTimerQueueTimer在C#中創建高分辨率計時器?
但timeSetEvent()
頁面推薦使用:
哪有我使用CreateTimerQueueTimer()在C#中每10毫秒執行一次方法?
我用一個Windows多媒體DLL來創建高分辨率定時器如何使用CreateTimerQueueTimer在C#中創建高分辨率計時器?
但timeSetEvent()
頁面推薦使用:
哪有我使用CreateTimerQueueTimer()在C#中每10毫秒執行一次方法?
傳遞給CreateTimerQueueTimer回調預計這將針對回調的壽命存在的非託管功能。託管代理可以在內存中移動,但是the underlying stub created by the marshalling will not do this so there is no need to pin the delegate。但是,由於來自非託管代碼的指針不足以使其保持活動狀態,因此需要保持代理不被垃圾收集。因此,您必須確保通過維護某個管理參考來保證代理處於活動狀態(也許通過使用GCHandle
傳遞給回調函數的PVOID參數必須在內存中固定,因爲再次,非託管函數期望它不會在函數返回後移動,在.Net中,這種鎖定會自動發生(高效),但僅用於被調用函數的生命週期。因此,如果您正在使用某個託管對象的引用(例如通過獲取IntPtr)底層的對象必須被固定(再次的GCHandle可以在一個微妙的不同的方式使用該)。爲了看看這是問題嘗試使用IntPtr.Zero作爲參數,以測試它是否工作。
如果這樣可以解決瘦gs你需要將參數分配爲非託管堆中的原始字節(並據此編組),使用一些可放入類型爲PVOID的安全類型(如Int32)或使用上面的GCHandle技術來維護指向託管實例的穩定指針,如果做錯了,這將會產生顯着的性能影響。
這裏是一個C#包裝的鏈接CreateTimerQueueTimer
:
(由Hobz
爲樣本類向下滾動到最後發表的文章)
我只是嘗試了這一點,我和它工作正常。不過,您需要添加的一件事是在啓動計時器之前致電timeBeginPeriod(1)
,以便將系統設置爲高分辨率。 timeSetEvent
內部調用timeBeginPeriod
,這就是爲什麼有些人錯誤地認爲它會創建一個更高分辨率的計時器。
最好使用timeSetEvent,因爲它的結果更加一致。在平均現代硬件上,對於較小的間隔,間隔長度的偏差比使用CreateTimerQueueTimer時小約十倍。假設你在調用CreateTimerQueueTimer之前不忘記增加定時器分辨率,否則差異會更大。因此改用timeSetEvent。
因爲InteropServices處理那些東西,所以通常不需要將委託傳遞給API函數。您*必須*確保您的應用程序維護對委託的引用,以便它不被垃圾收集。固定通常只有在將被管理的世界的大塊內存傳遞到非託管的世界(它希望事物留在原處)時纔是必需的。 – MusiGenesis 2010-03-25 14:01:09
@MusiGenesis,這就是我所說的「在.Net中,這幾乎肯定會發生在你傳入的任何東西上。」,我可能應該把它叫做PInvoke。同樣,我沒有理由提到需要保留引用,因爲如果需要的話,P/Invoke會爲你做這件事:http://msdn.microsoft.com/en-us/23acw07k.aspx – ShuggyCoUk 2010-03-26 15:33:15