How can I use CreateTimerQueueTimer to create a high resolution timer in C#?

后端 未结 3 1916
青春惊慌失措
青春惊慌失措 2021-01-18 05:54

I\'ve used a Windows multimedia dll to created a high resolution timer with

timSetEvent()

But the timeSetEvent() page recommends the use

相关标签:
3条回答
  • 2021-01-18 06:07

    The callback passed to CreateTimerQueueTimer is expected to be an unmanaged function which will exist for the lifetime of the callbacks. The managed delegate can move about in memory but the underlying stub created by the marshalling will not do this so there is no need to pin the delegate. There is however a need to keep the delegate from being garbage collected since the pointer from unmanaged code is not sufficient to keep it alive. You must therefore ensure that either the delegate is kept alive by some managed reference being maintained (Perhaps through the use of GCHandle

    The PVOID Parameter which is passed to the callback function must be fixed in memory since again, the unmanaged function expects it not to move about after the function returns. In .Net this pinning happens (efficiently) automatically but only for the life of the called function. Thus if you are using a reference to some managed object (say by getting an IntPtr to it) the underlying object must be pinned (again the GCHandle can be used for that in a subtly different way). To see if this is the problem try using IntPtr.Zero as the parameter to test if it works.

    If this solves things you will need to either allocate your parameter as raw bytes in the unmanaged heap (and marshal accordingly), use some blittable type that is safe to put into something of size PVOID (like an Int32) or use the GCHandle technique above to maintain a stable pointer to a managed instance, this will have significant performance implications if done wrongly.

    0 讨论(0)
  • 2021-01-18 06:15

    Here is a link to a C# wrapper for CreateTimerQueueTimer:

    http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/822aed2d-dca0-4a8e-8130-20fab69557d2

    (scroll down to the last post by Hobz for the sample class)

    I just tried this out myself and it works fine. One thing you'll need to add, though, is a call to timeBeginPeriod(1) before starting the timer in order to set your system to high-resolution. timeSetEvent calls timeBeginPeriod internally, which is why some people mistakenly assume that it creates a higher-resolution timer.

    0 讨论(0)
  • 2021-01-18 06:15

    It's better to use timeSetEvent because its results are more consistent. On average modern hardware, for small intervals, the deviations in length of the intervals are about ten times smaller than when using CreateTimerQueueTimer. And that's assuming you didn't forget to increase the timer resolution before calling CreateTimerQueueTimer, otherwise the difference would be even bigger. So use timeSetEvent instead.

    0 讨论(0)
提交回复
热议问题