using System;
namespace MicroLibrary
{
///
/// MicroStopwatch class
///
public class MicroStopwatch : System.Diagnostics.Stopwatch
{
readonly double _microSecPerTick =
1000000D / System.Diagnostics.Stopwatch.Frequency;
public MicroStopwatch()
{
if (!System.Diagnostics.Stopwatch.IsHighResolution)
{
throw new Exception("On this system the high-resolution " +
"performance counter is not available");
}
}
public long ElapsedMicroseconds
{
get
{
return (long)(ElapsedTicks * _microSecPerTick);
}
}
}
///
/// MicroTimer class
///
public class MicroTimer
{
public delegate void MicroTimerElapsedEventHandler(
object sender,
MicroTimerEventArgs timerEventArgs);
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
System.Threading.Thread _threadTimer = null;
long _ignoreEventIfLateBy = long.MaxValue;
long _timerIntervalInMicroSec = 0;
bool _stopTimer = true;
public MicroTimer()
{
}
public MicroTimer(long timerIntervalInMicroseconds)
{
Interval = timerIntervalInMicroseconds;
}
public long Interval
{
get
{
return System.Threading.Interlocked.Read(
ref _timerIntervalInMicroSec);
}
set
{
System.Threading.Interlocked.Exchange(
ref _timerIntervalInMicroSec, value);
}
}
public long IgnoreEventIfLateBy
{
get
{
return System.Threading.Interlocked.Read(
ref _ignoreEventIfLateBy);
}
set
{
System.Threading.Interlocked.Exchange(
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
}
}
public bool Enabled
{
set
{
if (value)
{
Start();
}
else
{
Stop();
}
}
get
{
return (_threadTimer != null && _threadTimer.IsAlive);
}
}
public void Start()
{
if (Enabled || Interval <= 0)
{
return;
}
_stopTimer = false;
System.Threading.ThreadStart threadStart = delegate()
{
NotificationTimer(ref _timerIntervalInMicroSec,
ref _ignoreEventIfLateBy,
ref _stopTimer);
};
_threadTimer = new System.Threading.Thread(threadStart);
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
_threadTimer.Start();
}
public void Stop()
{
_stopTimer = true;
}
public void StopAndWait()
{
StopAndWait(System.Threading.Timeout.Infinite);
}
public bool StopAndWait(int timeoutInMilliSec)
{
_stopTimer = true;
if (!Enabled || _threadTimer.ManagedThreadId ==
System.Threading.Thread.CurrentThread.ManagedThreadId)
{
return true;
}
return _threadTimer.Join(timeoutInMilliSec);
}
public void Abort()
{
_stopTimer = true;
if (Enabled)
{
_threadTimer.Abort();
}
}
void NotificationTimer(ref long timerIntervalInMicroSec,
ref long ignoreEventIfLateBy,
ref bool stopTimer)
{
int timerCount = 0;
long nextNotification = 0;
MicroStopwatch microStopwatch = new MicroStopwatch();
microStopwatch.Start();
while (!stopTimer)
{
long callbackFunctionExecutionTime =
microStopwatch.ElapsedMicroseconds - nextNotification;
long timerIntervalInMicroSecCurrent =
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
long ignoreEventIfLateByCurrent =
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
nextNotification += timerIntervalInMicroSecCurrent;
timerCount++;
long elapsedMicroseconds = 0;
while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
< nextNotification)
{
System.Threading.Thread.SpinWait(10);
}
long timerLateBy = elapsedMicroseconds - nextNotification;
if (timerLateBy >= ignoreEventIfLateByCurrent)
{
continue;
}
MicroTimerEventArgs microTimerEventArgs =
new MicroTimerEventArgs(timerCount,
elapsedMicroseconds,
timerLateBy,
callbackFunctionExecutionTime);
MicroTimerElapsed(this, microTimerEventArgs);
}
microStopwatch.Stop();
}
}
///
/// MicroTimer Event Argument class
///
public class MicroTimerEventArgs : EventArgs
{
// Simple counter, number times timed event (callback function) executed
public int TimerCount { get; private set; }
// Time when timed event was called since timer started
public long ElapsedMicroseconds { get; private set; }
// How late the timer was compared to when it should have been called
public long TimerLateBy { get; private set; }
// Time it took to execute previous call to callback function (OnTimedEvent)
public long CallbackFunctionExecutionTime { get; private set; }
public MicroTimerEventArgs(int timerCount,
long elapsedMicroseconds,
long timerLateBy,
long callbackFunctionExecutionTime)
{
TimerCount = timerCount;
ElapsedMicroseconds = elapsedMicroseconds;
TimerLateBy = timerLateBy;
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
}
}
}
private void MicroTimerTest()
{
// Instantiate new MicroTimer and add event handler
MicroLibrary.MicroTimer microTimer = new MicroLibrary.MicroTimer();
microTimer.MicroTimerElapsed +=
new MicroLibrary.MicroTimer.MicroTimerElapsedEventHandler(OnTimedEvent);
microTimer.Interval = 800; // Call micro timer every 1000µs (1ms)
// Can choose to ignore event if late by Xµs (by default will try to catch up)
// microTimer.IgnoreEventIfLateBy = 500; // 500µs (0.5ms)
microTimer.Enabled = true; // Start timer
// Do something whilst events happening, for demo sleep 2000ms (2sec)
System.Threading.Thread.Sleep(20000);
microTimer.Enabled = false; // Stop timer (executes asynchronously)
// Alternatively can choose stop here until current timer event has finished
// microTimer.StopAndWait(); // Stop timer (waits for timer thread to terminate)
// Wait for user input
Console.ReadLine();
}
private void OnTimedEvent(object sender,
MicroLibrary.MicroTimerEventArgs timerEventArgs)
{
// Do something small that takes significantly less time than Interval
Console.WriteLine(string.Format(
"Count = {0:#,0} Timer = {1:#,0} µs, " +
"LateBy = {2:#,0} µs, ExecutionTime = {3:#,0} µs",
timerEventArgs.TimerCount, timerEventArgs.ElapsedMicroseconds,
timerEventArgs.TimerLateBy, timerEventArgs.CallbackFunctionExecutionTime));
Console.ReadLine();
}