码迷,mamicode.com
首页 > Windows程序 > 详细

Windows高速定时器,多媒体定时器winmm.dll库的使用

时间:2017-08-15 21:00:39      阅读:281      评论:0      收藏:0      [点我收藏+]

标签:value   event   事件   use   images   回调函数   利用   key   extern   

技术分享

项目里面用到的这些看起来名字高大上的定时器测试下来也是非常不准。看了源码发现也是用System.Timers.Timer或者用的是Thread休眠的方式来实现的。100毫秒就不准了。直到一番搜索,发现利用多媒体定时器winmm.dll的MillisecondTimer是可用的。原文来自博客(dehai)Timer计时不准确的问题及解决方法”。代码如下:

 public sealed class MillisecondTimer : IComponent, IDisposable
    {
        //*****************************************************  字 段  *******************************************************************
        private static TimerCaps caps;
        private int interval;
        private bool isRunning;
        private int resolution;
        private TimerCallback timerCallback;
        private int timerID;

        //*****************************************************  属 性  *******************************************************************
        /// <summary>
        /// 
        /// </summary>
        public int Interval
        {
            get
            {
                return this.interval;
            }
            set
            {
                if ((value < caps.periodMin) || (value > caps.periodMax))
                {
                    throw new Exception("超出计时范围!");
                }
                this.interval = value;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return this.isRunning;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ISite Site
        {
            set;
            get;
        }

        //*****************************************************  事 件  *******************************************************************
        public event EventHandler Disposed;  // 这个事件实现了IComponet接口
        public event EventHandler Tick;
        //***************************************************  构造函数和释构函数  ******************************************************************

        static MillisecondTimer()
        {
            timeGetDevCaps(ref caps, Marshal.SizeOf(caps));
        }

        public MillisecondTimer()
        {
            this.interval = caps.periodMin;    // 
            this.resolution = caps.periodMin;  //
            this.isRunning = false;
            this.timerCallback = new TimerCallback(this.TimerEventCallback);
        }

        public MillisecondTimer(IContainer container)
            : this()
        {
            container.Add(this);
        }

        ~MillisecondTimer()
        {
            timeKillEvent(this.timerID);
        }

        //*****************************************************  方 法  *******************************************************************
        /// <summary>
        /// 
        /// </summary>
        public void Start()
        {
            if (!isRunning)
            {
                timerID = timeSetEvent(this.interval, this.resolution, this.timerCallback, 0, 1); // 间隔性地运行
                if (timerID == 0)
                {
                    throw new Exception("无法启动计时器");
                }
                isRunning = true;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Stop()
        {
            if (isRunning)
            {
                timeKillEvent(this.timerID);
                isRunning = false;
            }
        }

        /// <summary>
        /// 实现IDisposable接口
        /// </summary>
        public void Dispose()
        {
            timeKillEvent(this.timerID);
            GC.SuppressFinalize(this);
            Disposed?.Invoke(this, EventArgs.Empty);
        }

        //***************************************************  内部函数  ******************************************************************
        [DllImport("winmm.dll")]
        private static extern int timeSetEvent(int delay, int resolution, TimerCallback callback, int user, int mode);

        [DllImport("winmm.dll")]
        private static extern int timeKillEvent(int id);

        [DllImport("winmm.dll")]
        private static extern int timeGetDevCaps(ref TimerCaps caps, int sizeOfTimerCaps); 

        private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
        {
            Tick?.Invoke(this, null);  // 引发事件
        }
        //***************************************************  内部类型  ******************************************************************

        private delegate void TimerCallback(int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名

        /// <summary>
        /// 定时器的分辨率(resolution)。单位是ms,毫秒?
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct TimerCaps
        {
            public int periodMin;
            public int periodMax;
        }
    }
}

测试代码

 class Program
    {
        static Dictionary<string, int> dtList = new Dictionary<string, int>();
        static void Main(string[] args)
        {
            //var timer = new DoubleThreadTimer(100, 100);
            //timer.OnRunningCallback += Timer1_Tick;
            //timer.Start();

            var timer1 = new MillisecondTimer();
            timer1.Interval = 2;
            timer1.Tick += Timer1_Tick;
            timer1.Start();
            Console.ReadLine();
        }

        private static void Timer1_Tick(object sender, EventArgs e)
        {
            var dt = DateTime.Now;
            string dtStr = dt.ToString("yyyyMMdd HHmmss");
            if (dtList.ContainsKey(dtStr))
            {
                dtList[dtStr]++;
                if (dtList[dtStr] % 500 == 0)
                {                    
                    Console.WriteLine(dtStr + "--->" + dtList[dtStr]);
                    dtList.Remove(dtStr);
                } 
            }
            else
            {
                if (dtList.Count > 1)
                {
                    foreach (var item in dtList)
                    {
                        Console.WriteLine(item.Key + "--->" + item.Value); 
                    }
                    dtList.Clear();
                }
                dtList.Add(dtStr, 1);                
            }
        }
    }

  技术分享

测试结论: 时间间隔设置为5毫秒,表现很稳定。2毫秒有时准。可靠性比.net的timer准好多倍啊

 

Windows高速定时器,多媒体定时器winmm.dll库的使用

标签:value   event   事件   use   images   回调函数   利用   key   extern   

原文地址:http://www.cnblogs.com/datacool/p/datacool_2017timer.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!