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