美文网首页
C#高精度定时器

C#高精度定时器

作者: 安静的程序员 | 来源:发表于2020-05-26 12:51 被阅读0次

    因在项目中需要使用定时器播放帧动画,系统自带的定时器每秒最多执行60帧,因为误差较大,如果用于计时的任务,则会随着时间的增加,误差会变的越来越大。
    好在Windows系统提供了一种精度更高的定时器:多媒体定时器(Multimedia Timers),最高可以精确至1毫秒。
    微软官方文档:https://docs.microsoft.com/zh-cn/windows/win32/multimedia/multimedia-timers
    为了方便使用,我封装了一个库,下面是主要代码(完整代码请参考附件):

    namespace HighPrecisionTimer
    {
        /// <summary>
        /// 定时器分辨率:毫秒
        /// </summary>
        struct TimerCaps
        {
            /// <summary>最小周期</summary>
            public int periodMin;
            /// <summary>最大周期</summary>
            public int periodMax;
        }
    
        /// <summary>
        /// 高精度定时器
        /// </summary>
        public class HPTimer
        {
            static HPTimer()
            {
                TimeGetDevCaps(ref _caps, Marshal.SizeOf(_caps));
            }
    
            public HPTimer()
            {
                Running = false;
                _interval = _caps.periodMin;
                _resolution = _caps.periodMin;
                _callback = new TimerCallback(TimerEventCallback);
            }
    
            ~HPTimer()
            {
                TimeKillEvent(_id);
            }
    
            /// <summary>
            /// 系统定时器回调
            /// </summary>
            /// <param name="id">定时器编号</param>
            /// <param name="msg">预留,不使用</param>
            /// <param name="user">用户实例数据</param>
            /// <param name="param1">预留,不使用</param>
            /// <param name="param2">预留,不使用</param>
            private delegate void TimerCallback(int id, int msg, int user, int param1, int param2);
    
            #region 动态库接口
    
            /// <summary>
            /// 查询设备支持的定时器分辨率
            /// </summary>
            /// <param name="ptc">定时器分辨率结构体指针</param>
            /// <param name="cbtc">定时器分辨率结构体大小</param>
            /// <returns></returns>
            [DllImport("winmm.dll", EntryPoint = "timeGetDevCaps")]
            private static extern TimerError TimeGetDevCaps(ref TimerCaps ptc, int cbtc);
    
            /// <summary>
            /// 绑定定时器事件
            /// </summary>
            /// <param name="delay">延时:毫秒</param>
            /// <param name="resolution">分辨率</param>
            /// <param name="callback">回调接口</param>
            /// <param name="user">用户提供的回调数据</param>
            /// <param name="eventType"></param>
            [DllImport("winmm.dll", EntryPoint = "timeSetEvent")]
            private static extern int TimeSetEvent(int delay, int resolution, TimerCallback callback, int user, int eventType);
    
            /// <summary>
            /// 终止定时器
            /// </summary>
            /// <param name="id">定时器编号</param>
            [DllImport("winmm.dll", EntryPoint = "timeKillEvent")]
            private static extern TimerError TimeKillEvent(int id);
    
            #endregion
    
            #region 属性
    
            /// <summary>时间间隔:毫秒</summary>
            public int Interval
            {
                get { return _interval; }
                set
                {
                    if (value < _caps.periodMin || value > _caps.periodMax)
                        throw new Exception("无效的计时间隔");
                    _interval = value;
                }
            }
    
            public bool Running { get; private set; }
    
            #endregion
    
            #region 事件
    
            public event Action Ticked;
    
            #endregion
    
            #region 公开方法
    
            public void Start()
            {
                if (!Running)
                {
                    _id = TimeSetEvent(_interval, _resolution, _callback, 0,
                        (int)EventType01.TIME_PERIODIC | (int)EventType02.TIME_KILL_SYNCHRONOUS);
                    if (_id == 0) throw new Exception("启动定时器失败");
                    Running = true;
                }
            }
    
            public void Stop()
            {
                if (Running)
                {
                    TimeKillEvent(_id);
                    Running = false;
                }
            }
    
            #endregion
    
            #region 内部方法
    
            private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
            {
                Ticked?.Invoke();
            }
    
            #endregion
    
            #region 字段
    
            // 系统定时器分辨率
            private static TimerCaps _caps;
            // 定时器间隔
            private int _interval;
            // 定时器分辨率
            private int _resolution;
            // 定时器回调
            private TimerCallback _callback;
            // 定时器编号
            private int _id;
    
            #endregion
        }
    }
    

    完整项目:https://pan.baidu.com/s/1Lz6PbGsj4If0Y8jbdaQigg
    提取码:jkl2

    相关文章

      网友评论

          本文标题:C#高精度定时器

          本文链接:https://www.haomeiwen.com/subject/hjbmahtx.html