c# 高精度的timer

时间:2023-01-22 08:56:03

核心代码摘自 http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer

想用c# (winform)做一个毫秒级别的计时器,发现微软自带的Timer控件经度不够。找到了这段代码,大意是用的 类 System.Diagnostics.Stopwatch 做了一个进一步的封装。

代码和用法例子如下

using System;
namespace MicroLibrary
{
/// <summary>
/// MicroStopwatch class
/// </summary>
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);
}
}
}

/// <summary>
/// MicroTimer class
/// </summary>
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();
}
}

/// <summary>
/// MicroTimer Event Argument class
/// </summary>
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;
}

}

}

应用Demo

public partial class Form1 : Form
{
MicroLibrary.MicroTimer microTimer
= null;
public Form1()
{
InitializeComponent();
MicroTimerTest();
}
private void MicroTimerTest()
{
// Instantiate new MicroTimer and add event handler
microTimer = new MicroLibrary.MicroTimer();
microTimer.MicroTimerElapsed
+= new MicroLibrary.MicroTimer.MicroTimerElapsedEventHandler(OnTimedEvent);
microTimer.Interval
= 1000; // Call micro timer every 1000µs (1ms)
}
int i = 0;
private void OnTimedEvent(object sender, MicroLibrary.MicroTimerEventArgs timerEventArgs)
{
  if (this.IsHandleCreated)
            {
this.BeginInvoke(new MethodInvoker(delegate
{
this.textBox1.Text = i.ToString();
}));
i
++;
} }
private void btnStart_Click(object sender, EventArgs e)
{
microTimer.Enabled
= true;
}
private void btnStop_Click(object sender, EventArgs e)
{
microTimer.Abort(); microTimer.Enabled
= false;
}
}