using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SIASUN.Autopilot.Device.Common
{
///
/// 基于系统性能计数器的定时器,计数单位是1微秒=1/1000毫秒
/// 注意:该定时器会独占一个CPU核心,尝试定时器与主程序运行在同一核心将导致程序失去响应
///
public class MTimer
{
///
/// 获取当前系统性能计数
///
///
///
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
///
/// 获取当前系统性能频率
///
///
///
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
///
/// 指定某一特定线程运行在指定的CPU核心
///
///
///
///
[DllImport("kernel32.dll")]
static extern UIntPtr SetThreadAffinityMask(IntPtr hThread, UIntPtr dwThreadAffinityMask);
///
/// 获取当前线程的Handler
///
///
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
///
/// 是否销毁定时器
///
private bool _Dispose = false;
///
/// 是否正在运行定时器
///
private bool _BRunTimer = false;
///
/// 首次启动延时(微秒)
///
private uint _Delay = 0;
///
/// 定时器周期(微秒)
///
private long _Period = 10;
///
/// 定时器运行时独占的CPU核心索引序号
///
private byte _CpuIndex = 0;
///
/// 系统性能计数频率(每秒)
///
private long _Freq = 0;
///
/// 系统性能计数频率(每微秒)
///
private long _Freqmms = 0;
///
/// 回调函数定义
///
private OnTickHandle Tick;
///
/// 根据CPU的索引序号获取CPU的标识序号
///
///
///
private ulong GetCpuID(int idx)
{
ulong cpuid = 0;
if (idx < 0 || idx >= System.Environment.ProcessorCount)
{
idx = 0;
}
cpuid |= 1UL << idx;
return cpuid;
}
///
/// 定时器构造函数
///
/// 首次启动定时器延时时间(微秒)
/// 定时器触发的周期(微秒)
/// 指定定时器线程独占的CPU核心索引,必须>0,不允许为定时器分配0#CPU
/// 定时器触发时的回调函数
public MTimer(uint delay, uint period, byte cpuIndex, OnTickHandle tick)
{
Tick = tick;
_Delay = delay;
_Period = period;
_CpuIndex = cpuIndex;
long freq = 0;
QueryPerformanceFrequency(out freq);
if (freq > 0)
{
_Freq = freq;
_Freqmms = freq / 1000000;//每微秒性能计数器跳跃次数
}
else
{
throw new Exception("初始化定时器失败");
}
if (_CpuIndex == 0)
{
throw new Exception("定时器不允许被分配到0#CPU");
}
if (_CpuIndex >= System.Environment.ProcessorCount)
{
throw new Exception("为定时器分配了超出索引的CPU");
}
}
private System.Threading.Thread _threadRumTimer;
///
/// 开启定时器
///
public void Open()
{
if (Tick != null)
{
_threadRumTimer = new System.Threading.Thread(new System.Threading.ThreadStart(RunTimer));
_threadRumTimer.Start();
}
}
///
/// 运行定时器
///
private void RunTimer()
{
UIntPtr up = UIntPtr.Zero;
if (_CpuIndex != 0)
up = SetThreadAffinityMask(GetCurrentThread(), new UIntPtr(GetCpuID(_CpuIndex)));
if (up == UIntPtr.Zero)
{
throw new Exception("为定时器分配CPU核心时失败");
}
long q1, q2;
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
if (_Delay > 0)
{
while (q2 < q1 + _Delay * _Freqmms)
{
QueryPerformanceCounter(out q2);
}
}
QueryPerformanceCounter(out q1);
QueryPerformanceCounter(out q2);
while (!_Dispose)
{
_BRunTimer = true;
QueryPerformanceCounter(out q2);
if (q2 > q1 + _Freqmms * _Period)
{
//***********回调***********//
if (!_Dispose)
Tick(this, (q2 - q1) / (_Freqmms * _Period), (q2 - q1) / _Freqmms);
q1 = q2;
//System.Windows.Forms.Application.DoEvents();//会导致线程等待windows消息循环,时间损失15ms以上
}
_BRunTimer = false;
}
}
///
/// 销毁当前定时器所占用的资源
///
public void Dispose()
{
_Dispose = true;
while (_BRunTimer)
System.Windows.Forms.Application.DoEvents();//在工作未完成之前,允许处理消息队列,防止调用者挂起
if (_threadRumTimer != null)
_threadRumTimer.Abort();
}
///
/// 定时器事件的委托定义
///
/// 事件的发起者,即定时器对象
/// 上次调用和本次调用跳跃的周期数
/// 上次调用和本次调用之间的间隔时间(微秒)
public delegate void OnTickHandle(object sender, long JumpPeriod, long interval);
}
}