欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 创建高精度定时器的示例

程序员文章站 2022-04-06 22:06:18
背景我们知道在.net framework中存在四种常用的定时器,他们分别是:1两个是通用的多线程定时器: system.threading.timer system.timers.timer...

背景

 我们知道在.net framework中存在四种常用的定时器,他们分别是:

1 两个是通用的多线程定时器:

  • system.threading.timer
  • system.timers.timer

2 两个是专用的单线程定时器

  • system.windows.forms.timer (windows forms 的定时器)
  • system.windows.threading.dispatchertimer (wpf 的定时器)

通常他们的精度只能维持在10-20ms之间,这个和操作系统相关,所以我们在很多场景下面这个是不能够达到我们精度的要求的,如果要实现这一需求我们该怎么办,当然也有很多办法,今天主要介绍一种stopwatch来实现的方式,网上有很多采用win32 dll的api这个当然是可以的,这篇文章的重点不是去讨论这个,关于使用win32 api的方式可以参考这里。

实现

using system;
using system.collections.generic;
using system.diagnostics;
using system.linq;
using system.runtime.interopservices;
using system.text;
 
namespace pangea.common.utility
{
    /// <summary>
    /// .net stopwatch对高精度定时器作了很好的包装
    /// devicetimer内部采用stopwatch类实现高精度定时操作
    /// </summary>
    public sealed class devicetimer
    {
#if use_cpu_counting
        //引入高性能计数器api,通过对cpu计数完成计时
        [dllimport("kernel32.dll")]
        private static extern bool queryperformancecounter(out long lpperformancecount);
 
        //获取当前cpu的工作频率
        [dllimport("kernel32.dll")]
        private static extern bool queryperformancefrequency(out long lpfrequency);
#else
        /// <summary>
        /// 获取tickcount64计数
        /// </summary>
        /// <returns></returns>
        //[dllimport("kernel32.dll")]
        //public static extern long gettickcount64();
#endif
        private enum devicetimerstate
        {
            tm_st_idle = 0,
            tm_st_busy = 1,
            tm_st_timeout = 2,
        }
 
        /// <summary>
        /// stopwatch object
        /// </summary>
        stopwatch _stopwatch = new stopwatch();
 
        /// <summary>
        /// 定时器内部状态
        /// </summary>
        devicetimerstate _state;
 
        /// <summary>
        /// 定时器开始计时时刻的相对时间点
        /// </summary>
        long _starttime;
 
        /// <summary>
        /// 定时器超时时刻的相对时间点
        /// </summary>
        long _timeout;
 
#if use_cpu_counting
 
        /// <summary>
        /// cpu运行的时钟频率
        /// </summary>
        double _freq;
#endif
 
        /// <summary>
        /// 定时时间(单位:ms)
        /// </summary>
        double _duration;
 
        /// <summary>
        /// class constructure
        /// </summary>
        public devicetimer()
        {
#if use_cpu_counting
            long freq;
            if (queryperformancefrequency(out freq) == false)
                throw new exception("本计算机不支持高性能计数器");
            //得到每1ms的cpu计时tickcount数目
            _freq = (double)freq / 1000.0;
            queryperformancecounter(out _starttime);
#else
            _stopwatch.start();
            _starttime = 0;
#endif
            setstate(devicetimerstate.tm_st_idle);
            _timeout = _starttime;
            _duration = 0;
        }
 
        /// <summary>
        /// 内部调用:设置定时器当前状态
        /// </summary>
        /// <param name="state"></param>
        private void setstate(devicetimerstate state)
        {
            _state = state;
        }
 
        /// <summary>
        /// 内部调用:返回定时器当前状态
        /// </summary>
        /// <returns></returns>
        private devicetimerstate getstate()
        {
            return _state;
        }
 
        /// <summary>
        /// 定时器开始计时到现在已流逝的时间(单位:毫秒)
        /// </summary>
        /// <returns></returns>
        public double getelapsetime()
        {
            long curcount;
#if use_cpu_counting
            queryperformancecounter(out curcount);
            return (double)(curcount - _starttime) / (double)_freq;
#else
            curcount = _stopwatch.elapsedmilliseconds;
            return curcount - _starttime;
#endif
        }
 
        /// <summary>
        /// 获取定时总时间
        /// </summary>
        /// <returns></returns>
        public double gettotaltime()
        {
            return _duration;
        }
 
        /// <summary>
        /// 停止计时器计时
        /// </summary>
        public void stop()
        {
            setstate(devicetimerstate.tm_st_idle);
#if use_cpu_counting
            queryperformancecounter(out _starttime);
#else
            _starttime = _stopwatch.elapsedmilliseconds;
#endif
            _timeout = _starttime;
            _duration = 0;
        }
 
        /// <summary>
        /// 启动定时器
        /// </summary>
        /// <param name="delay_ms">定时时间(单位:毫秒)</param>
        public void start(double delay_ms)
        {
#if use_cpu_counting
            queryperformancecounter(out _starttime);
            _timeout = convert.toint64(_starttime + delay_ms * _freq);
#else
            _starttime = _stopwatch.elapsedmilliseconds;
            _timeout = convert.toint64(_starttime + delay_ms);
#endif
            setstate(devicetimerstate.tm_st_busy);
            _duration = delay_ms;
        }
 
        /// <summary>
        /// 重新开始定时器
        /// 开始的计时时间以上一次start的时间为准
        /// </summary>
        /// <param name="delay_ms">定时时间(单位:毫秒)</param>
        public void restart(double delay_ms)
        {
#if use_cpu_counting
            _timeout = convert.toint64(_starttime + delay_ms * _freq);
#else
            _timeout = convert.toint64(_starttime + delay_ms);
#endif
            setstate(devicetimerstate.tm_st_busy);
            _duration = delay_ms;
        }
 
        /// <summary>
        /// 返回定时器是否超时
        /// </summary>
        /// <returns></returns>
        public bool istimeout()
        {
            if (_state == devicetimerstate.tm_st_idle)
            {
                //system.diagnostics.debug.writeline("warning: misuage of the device timer. you must start it first before you can use it.");
                //system.diagnostics.debug.assert(false, "warning: misuage of the device timer. you must start it first before you can use it.");
            }
            long curcount;
#if use_cpu_counting
            queryperformancecounter(out curcount);
#else
            curcount = _stopwatch.elapsedmilliseconds;
#endif
            if (_state == devicetimerstate.tm_st_busy && (curcount >= _timeout))
            {
                setstate(devicetimerstate.tm_st_timeout);
                return true;
            }
            else if (_state == devicetimerstate.tm_st_timeout)
            {
                return true;
            }
            return false;
        }
 
        /// <summary>
        /// 定时器是否在工作中
        /// </summary>
        /// <returns></returns>
        public bool isidle()
        {
            return (_state == devicetimerstate.tm_st_idle);
        }
    }
}

  这个里面我们在devicetimer中定义了一个私有的_stopwatch 对象并且在构造函数中就启动了这个stopwatch,所以我们在使用的时候是通过先创建一个deveicetimer的对象然后我们再调用内部的start方法,当然在调用这个方法的时候我们需要传入一个定时时间,然后不断检测istimeout方法看是否到达定时时间,从而达到类似于定时时间到的效果,另外getelapsetime()方法能够获取从调用start方法开始到现在的时间,另外我们还在其中定义了几个枚举值用来表示当前devicetimer的状态用于做一些状态的校验,具体数值如下。

private enum devicetimerstate
{
    tm_st_idle = 0,
    tm_st_busy = 1,
    tm_st_timeout = 2,
}

  这里还有最后一个问题就是循环调用的问题,这个其实也是非常简单就在一个while循环中不断进行调用,当然下面的代码可以有很多内容供我们去发挥的,这个可以根据自己的需要进行修改。

using system;
using system.threading.tasks;
 
namespace devicetimerconsoleapp
{
    class program
    {
        private static bool flag = true;
        static void main(string[] args)
        {
            task.factory.startnew(() =>
            {
                var devicetimer = new devicetimer();
                devicetimer.start(5);
 
                while (flag)
                {
                    if (devicetimer.istimeout())
                    {
                        console.writeline($"定时时间已到,距离开始执行已过去:{devicetimer.getelapsetime()}ms");
 
                        devicetimer.start(5);
                    }
                }
            });
            console.readkey();
        }
    }
     
}

  我们来看看定时器的效果

C# 创建高精度定时器的示例

以上就是c# 创建高精度定时器的示例的详细内容,更多关于c# 创建高精度定时器的资料请关注其它相关文章!