我使用了Windows多媒体dll创建了一个高分辨率计时器,使用了 timeSetEvent() 方法。
但是 timeSetEvent()
页面建议使用:
如何在C#中使用CreateTimerQueueTimer()每10毫秒执行一次方法?
我使用了Windows多媒体dll创建了一个高分辨率计时器,使用了 timeSetEvent() 方法。
但是 timeSetEvent()
页面建议使用:
如何在C#中使用CreateTimerQueueTimer()每10毫秒执行一次方法?
CreateTimerQueueTimer
的链接:
http://social.msdn.microsoft.com/Forums/en-CA/csharpgeneral/thread/822aed2d-dca0-4a8e-8130-20fab69557d2
(向下滚动到Hobz
的最后一篇帖子中获取示例类)timeBeginPeriod(1)
来设置您的系统为高分辨率。因为timeSetEvent
内部会调用timeBeginPeriod
,这就是为什么有些人错误地认为它创建了更高分辨率的定时器。CreateTimerQueueTimer函数传递的回调函数应该是一个未托管的函数,它将存在于回调函数的生命周期中。托管委托可以在内存中移动,但由封送创建的基础存根不会这样做,因此无需固定委托。然而,需要防止委托被垃圾回收,因为来自未托管代码的指针不足以保持其活动状态。因此,您必须确保通过维护某些托管引用(例如使用GCHandle)来保留委托。
传递给回调函数的PVOID参数必须在内存中固定,因为非托管函数希望在函数返回后它不会移动。在.Net中,这种固定是自动进行的,但仅在被调用的函数的生命周期内。因此,如果您正在使用对某些托管对象的引用(例如通过获取它的IntPtr),则底层对象必须被固定(GCHandle可以以略微不同的方式用于此)。要查看是否存在此问题,请尝试使用IntPtr.Zero作为参数来测试是否有效。new TimerCallback(...)
作为参数传递。这甚至可以成功运行一段时间,直到您使用new
创建的委托恰好被垃圾回收。 - MusiGenesisGCHandle
来固定委托以便使用CreateTimerQueueTimer
。实际上,您不能使用GCHandle
来固定委托。 - MusiGenesis使用timeSetEvent更好,因为其结果更加一致。在现代硬件上,对于小间隔,时间间隔长度的偏差约为使用CreateTimerQueueTimer时的十倍小。而且这还是假设在调用CreateTimerQueueTimer之前没有忘记增加计时器分辨率的情况下,否则差异会更大。因此,请使用timeSetEvent。