Initial commit
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RobotNet10.RobotApp.Services.Robot;
|
||||
|
||||
internal static partial class Windows
|
||||
{
|
||||
[LibraryImport("winmm.dll")]
|
||||
internal static partial uint timeBeginPeriod(uint uPeriod);
|
||||
|
||||
[LibraryImport("winmm.dll")]
|
||||
internal static partial uint timeEndPeriod(uint uPeriod);
|
||||
}
|
||||
|
||||
public static class HighPrecisionTimerHelper
|
||||
{
|
||||
public static void EnableHighPrecision()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
_ = Windows.timeBeginPeriod(2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DisableHighPrecision()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
_ = Windows.timeEndPeriod(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HighPrecisionTimer<T>(int Interval, Action Callback, Logger<T>? Logger) : IDisposable where T : class
|
||||
{
|
||||
public bool Disposed;
|
||||
private Thread? Thread;
|
||||
private long IntervalTicks;
|
||||
private long NextDueTime;
|
||||
private readonly Lock Lock = new();
|
||||
|
||||
private void Handler()
|
||||
{
|
||||
while (!Disposed)
|
||||
{
|
||||
long now = Stopwatch.GetTimestamp();
|
||||
|
||||
bool shouldRun = false;
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
if (Disposed) break;
|
||||
if (now >= NextDueTime)
|
||||
{
|
||||
shouldRun = true;
|
||||
long scheduledTime = NextDueTime;
|
||||
NextDueTime += IntervalTicks;
|
||||
|
||||
// Tự đồng bộ nếu lệch quá
|
||||
long driftTicks = now - scheduledTime;
|
||||
if (driftTicks > IntervalTicks / 2)
|
||||
{
|
||||
Logger?.Warning($"High-res timer drift: {driftTicks * 1000.0 / Stopwatch.Frequency:F3}ms. Resync.");
|
||||
NextDueTime = now + IntervalTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === BƯỚC 2: Chạy callback ===
|
||||
if (shouldRun)
|
||||
{
|
||||
try
|
||||
{
|
||||
Callback.Invoke();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"Callback error in high-precision timer: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
// === BƯỚC 3: Chờ chính xác đến lần sau ===
|
||||
long sleepUntil = NextDueTime;
|
||||
while (!Disposed)
|
||||
{
|
||||
now = Stopwatch.GetTimestamp();
|
||||
long remaining = sleepUntil - now;
|
||||
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
|
||||
// > 1ms → Sleep
|
||||
if (remaining > Stopwatch.Frequency / 1000)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
// < 1ms → SpinWait
|
||||
else
|
||||
{
|
||||
Thread.SpinWait((int)(remaining / 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (!Disposed)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
if (Interval < 30) HighPrecisionTimerHelper.EnableHighPrecision();
|
||||
IntervalTicks = (long)(Interval * (Stopwatch.Frequency / 1000.0));
|
||||
Thread = new Thread(Handler) { IsBackground = true, Priority = ThreadPriority.Highest };
|
||||
NextDueTime = Stopwatch.GetTimestamp() + IntervalTicks;
|
||||
Thread.Start();
|
||||
}
|
||||
}
|
||||
else throw new ObjectDisposedException(nameof(HighPrecisionTimer<T>));
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (Disposed) return;
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
Disposed = true;
|
||||
lock (Lock)
|
||||
{
|
||||
Thread.Join(100);
|
||||
Thread = null;
|
||||
HighPrecisionTimerHelper.DisableHighPrecision();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed) return;
|
||||
|
||||
if (disposing) Stop();
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
~HighPrecisionTimer()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user