bas*_*bas 5 c# timer high-resolution
是否存在高分辨率计时器,每次计时器过去时都会引发事件,就像System.Timer课程一样?Elapse每隔ms 我需要一个高分辨率计时器.
我一直在发帖说明秒表可以测量高分辨率,但我不想测量时间,我想创建一个1毫秒的间隔.
在.NET中有什么东西,还是我要编写自己的高分辨率计时器?
Mik*_*ray 12
我所知道的.NET框架中没有任何内置功能.Windows具有通过Multimedia Timer API实现高分辨率计时器事件的机制.下面是一个快速的例子我掀起了似乎做这个工作.也有似乎是一个很好的例子在这里.
我会注意到这个API改变了系统范围的设置,这会降低系统性能,所以买家要小心.出于测试目的,我建议跟踪定时器触发的频率,以验证定时与您尝试模拟的设备类似.由于Windows不是实时操作系统,因此系统上的负载可能导致MM定时器延迟,导致100 ms的间隙快速连续包含100个事件,而不是间隔1 ms的100个事件.关于MM计时器的一些额外阅读.
class Program
{
static void Main(string[] args)
{
TestThreadingTimer();
TestMultimediaTimer();
}
private static void TestMultimediaTimer()
{
Stopwatch s = new Stopwatch();
using (var timer = new MultimediaTimer() { Interval = 1 })
{
timer.Elapsed += (o, e) => Console.WriteLine(s.ElapsedMilliseconds);
s.Start();
timer.Start();
Console.ReadKey();
timer.Stop();
}
}
private static void TestThreadingTimer()
{
Stopwatch s = new Stopwatch();
using (var timer = new Timer(o => Console.WriteLine(s.ElapsedMilliseconds), null, 0, 1))
{
s.Start();
Console.ReadKey();
}
}
}
public class MultimediaTimer : IDisposable
{
private bool disposed = false;
private int interval, resolution;
private UInt32 timerId;
// Hold the timer callback to prevent garbage collection.
private readonly MultimediaTimerCallback Callback;
public MultimediaTimer()
{
Callback = new MultimediaTimerCallback(TimerCallbackMethod);
Resolution = 5;
Interval = 10;
}
~MultimediaTimer()
{
Dispose(false);
}
public int Interval
{
get
{
return interval;
}
set
{
CheckDisposed();
if (value < 0)
throw new ArgumentOutOfRangeException("value");
interval = value;
if (Resolution > Interval)
Resolution = value;
}
}
// Note minimum resolution is 0, meaning highest possible resolution.
public int Resolution
{
get
{
return resolution;
}
set
{
CheckDisposed();
if (value < 0)
throw new ArgumentOutOfRangeException("value");
resolution = value;
}
}
public bool IsRunning
{
get { return timerId != 0; }
}
public void Start()
{
CheckDisposed();
if (IsRunning)
throw new InvalidOperationException("Timer is already running");
// Event type = 0, one off event
// Event type = 1, periodic event
UInt32 userCtx = 0;
timerId = NativeMethods.TimeSetEvent((uint)Interval, (uint)Resolution, Callback, ref userCtx, 1);
if (timerId == 0)
{
int error = Marshal.GetLastWin32Error();
throw new Win32Exception(error);
}
}
public void Stop()
{
CheckDisposed();
if (!IsRunning)
throw new InvalidOperationException("Timer has not been started");
StopInternal();
}
private void StopInternal()
{
NativeMethods.TimeKillEvent(timerId);
timerId = 0;
}
public event EventHandler Elapsed;
public void Dispose()
{
Dispose(true);
}
private void TimerCallbackMethod(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2)
{
var handler = Elapsed;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
private void CheckDisposed()
{
if (disposed)
throw new ObjectDisposedException("MultimediaTimer");
}
private void Dispose(bool disposing)
{
if (disposed)
return;
disposed = true;
if (IsRunning)
{
StopInternal();
}
if (disposing)
{
Elapsed = null;
GC.SuppressFinalize(this);
}
}
}
internal delegate void MultimediaTimerCallback(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);
internal static class NativeMethods
{
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent")]
internal static extern UInt32 TimeSetEvent(UInt32 msDelay, UInt32 msResolution, MultimediaTimerCallback callback, ref UInt32 userCtx, UInt32 eventType);
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeKillEvent")]
internal static extern void TimeKillEvent(UInt32 uTimerId);
}
Run Code Online (Sandbox Code Playgroud)