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