Most Accurate Timer in .Net

Most accurate timer in .NET?

For exact time measuring you need to use the Stopwatch class
MSDN

What's the most precise timer in .NET?

Use the System.Timer Class. Since it's designed for multi-threaded environments it's more accurate than the timer control.

High resolution timer in C#

There is nothing built into the .NET framework that I am aware of. Windows has a mechanism for high resolution timer events via the Multimedia Timer API. Below is a quick example I whipped up which seems to do the job. There are also seems to be a good example here.

I will note that this API changes system wide settings that can degrade system performance, so buyer beware. For testing purposes, I would recommend keeping track of how often the timer is firing to verify the timing is similar to the device you are trying to simulate. Since windows is not a real-time OS, the load on your system may cause the MM timer be delayed resulting in gaps of 100 ms that contain 100 events in quick succession, rather than 100 events spaced 1 ms apart. Some additional reading on MM timers.

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);
}

High resolution timer

I found a solution to this problem in the following blog:
http://web.archive.org/web/20110910100053/http://www.indigo79.net/archives/27#comment-255

It tells you how to use the multimedia timer to have a timer with high frequency. It is working just fine for me!!!

WPF - A more accurate Timer

Definitely. Take a look at the System.Diagnostics.Stopwatch class. You're re-inventing the wheel!

c# timer not accurate ?

No. The timer is not accurate at all. That is not its intended purpose. It will take at least the time you set as interval.

The 'problem' is: the thread the timer runs on is parked after the tick occurred. Then the processor takes some other work to do and comes back after some time when that job is done and makes the next tick. That is why such timers are not accurate.

To solve issue with that, you can sometimes calculate the difference between start and now and use that instead of counting the ticks.

Does a more accurate Timers.Timer from c# exists in c++?

Using a corrected timer class from Raise event in high resolution interval/timer, here is an example implementation of a high-resolution timer:

class Program
{
public void Main(string[] args)
{
uint timerId = SafeNativeMethods.timeSetEvent( 1, 1, HandleTimerTick, UIntPtr.Zero, 1 );
Console.ReadLine();
SafeNativeMethods.timeKillEvent( timerId );
}

public static void HandleTimerTick( uint id, uint msg, UIntPtr userCtx, UIntPtr uIntPtr, UIntPtr intPtr )
{
Console.WriteLine( "This is a bad idea on short timescales" );
}
}

public static class SafeNativeMethods
{
/// <summary>
/// A timer event handler
/// </summary>
/// <param name="id">Timer identifier, as returned by the timeSetEvent function.</param>
/// <param name="msg">Reserved</param>
/// <param name="userCtx">The value that was passed in to the userCtx value of the timeSetEvent function.</param>
/// <param name="dw1">Reserved</param>
/// <param name="dw2">Reserved</param>
public delegate void TimerEventHandler( UInt32 id, UInt32 msg, UIntPtr userCtx, UIntPtr dw1, UIntPtr dw2 );
/// <summary>
/// A multi media timer with millisecond precision
/// </summary>
/// <param name="msDelay">One event every msDelay milliseconds</param>
/// <param name="msResolution">Timer precision indication (lower value is more precise but resource unfriendly)</param>
/// <param name="handler">delegate to start</param>
/// <param name="userCtx">callBack data </param>
/// <param name="eventType">one event or multiple events</param>
/// <remarks>Dont forget to call timeKillEvent!</remarks>
/// <returns>0 on failure or any other value as a timer id to use for timeKillEvent</returns>
[DllImport( "winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent" )]
public static extern UInt32 timeSetEvent( UInt32 msDelay, UInt32 msResolution, TimerEventHandler handler, UIntPtr userCtx, UInt32 eventType );

/// <summary>
/// The multi media timer stop function
/// </summary>
/// <param name="uTimerID">timer id from timeSetEvent</param>
/// <remarks>This function stops the timer</remarks>
[DllImport( "winmm.dll", SetLastError = true )]
public static extern void timeKillEvent( UInt32 uTimerID );
}

Please be sure to kill your timer cleanly, using timeKillEvent, when you are done with it, and PLEASE don't use a ton of these timers in your application. They are resource-intensive.

What is the maximum precision of the Timer in .NET?

Windows desktop OSes really aren't accurate below about 40ms. The OS simply isn't real time and therefore presents significant non-deterministic jitter. What that means is that while it may report values down to the millisecond or even smaller, you can't really count on those values to be really meaningful. So even if the Timer interval gets set to some sub-millisecond value, you can't rely on times between setting and firing to actually be what you said you wanted.

Add to this fact that the entire framework you're running under is non-deterministic (the GC could suspend you and do collection duing the time when the Timer should fire) and you end up with loads and loads of risk trying to do anything that is time critical.



Related Topics



Leave a reply



Submit