我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何在C#中创建一个高精度的定时器

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何在C#中创建一个高精度的定时器

如何在C#中创建一个高精度的定时器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

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#中创建一个高精度的定时器的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何在C#中创建一个高精度的定时器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何在C#中创建一个高精度的定时器

如何在C#中创建一个高精度的定时器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1 两个是通用的多线程定时器:System.Threading.TimerSystem.Time
2023-06-06

如何在Android项目中创建一个自定义控件

本篇文章为大家展示了如何在Android项目中创建一个自定义控件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1、仿iPhone 的风格,在界面的顶部放置一个标题栏。2023-05-31

如何创建一个新的数据库在PostgreSQL中

要在PostgreSQL中创建一个新的数据库,可以使用以下步骤:打开命令行界面或者使用图形用户界面工具连接到PostgreSQL数据库。输入以下命令来创建一个新的数据库:CREATE DATABASE database_name;例如,要创
如何创建一个新的数据库在PostgreSQL中
2024-04-09

如何在Go语言中创建一个必要的包

如何在Go语言中创建一个必要的包在Go语言中,包是组织代码的基本单元,它可以包含多个相关的函数、变量和类型定义。创建一个必要的包是每个Go语言程序员都需要掌握的基本技能。本文将演示如何在Go语言中创建一个必要的包,并提供具体的代码示例。
如何在Go语言中创建一个必要的包
2024-03-15

如何在 Go 中创建一个共享内存的 Goroutine?

可以通过 channel 实现共享内存的 goroutine:创建一个 channel 以指定元素类型。启动一个 goroutine 向 channel 写入数据。在主 goroutine 中使用 range 循环从 channel 读取数
如何在 Go 中创建一个共享内存的 Goroutine?
2024-05-16

如何创建一个新的用户在Oracle数据库中

要在Oracle数据库中创建一个新用户,可以按照以下步骤进行:以具有创建用户权限的用户登录到Oracle数据库中。使用以下语法创建新用户:CREATE USER username IDENTIFIED BY password;其中,user
如何创建一个新的用户在Oracle数据库中
2024-04-09

如何在C#项目中创建一个Lambda表达式和Lambda表达式树

如何在C#项目中创建一个Lambda表达式和Lambda表达式树?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1、表达式Lambda  表达式位于 => 运算符右侧的 la
2023-06-06

如何在MySQL中创建一个高效的会计系统表结构以处理大量的数据?

如何在MySQL中创建一个高效的会计系统表结构以处理大量的数据?在现代商业中,会计系统扮演着重要的角色,用于记录和管理大量的财务数据。而在MySQL数据库中,如何设计高效的表结构来处理这些数据成为了一个关键问题。本文将介绍一种针对会计系统的
如何在MySQL中创建一个高效的会计系统表结构以处理大量的数据?
2023-10-31

C语言如何在字符串中搜索指定字符中的任意一个

C语言提供strchr()和strcspn()函数在字符串中查找指定字符中的任意一个。strchr()查找第一个匹配字符并返回其指针,而strcspn()查找第一个不在指定字符集中的字符并返回其距离字符串开头的长度。
C语言如何在字符串中搜索指定字符中的任意一个
2024-04-02

如何在MySQL中设计一个性能优化的会计系统表结构以提高查询和报表生成速度?

如何在MySQL中设计一个性能优化的会计系统表结构以提高查询和报表生成速度?在现代企业的会计系统中,数据量庞大且复杂,频繁的查询和报表生成是常见的需求。为了提高系统的性能和响应速度,设计一个优化的数据库表结构是至关重要的。规范化数据库表结构
如何在MySQL中设计一个性能优化的会计系统表结构以提高查询和报表生成速度?
2023-10-31

C语言如何规定当解析器在 XML 文档中找到符号声明时被调用的函数

C语言规定了当解析器在XML文档中找到符号声明时,将调用xmlSAXDeclHandler函数,其原型为:voidxmlSAXDeclHandler(voiduserData,constxmlCharversion,constxmlCharencoding,constxmlCharstandalone)该函数用于处理符号声明,包括存储版本、编码和独立性信息,执行验证和调整后续解析行为。应用程序可以通过xmlSAXSetDeclHandler注册解析器函数,从而实现可扩展性、可复用性和效率。
C语言如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
2024-04-02

C语言如何规定当解析器在 XML 文档中找到处理指令时所调用的函数

本文介绍了C语言中如何使用函数处理XML文档中的处理指令。当解析器遇到处理指令时,会调用XML处理指令函数规范中的函数。这些函数处理指令的开始和结束,以及指令的内容。步骤包括注册函数、解析XML文档和处理指令。示例代码展示了如何使用这些函数。应用程序包括自定义XML验证、处理DTD和XML转换。
C语言如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
2024-04-02

C语言如何规定当解析器在 XML 文档中找到外部实体时被调用的函数

摘要:本文介绍了C语言中如何使用expat库,为XML解析器设置处理外部实体的函数。外部实体是指存储在外部文件中的数据,当解析器在XML文档中遇到它们时会调用解析器函数。解析器函数负责加载和解析外部数据,返回成功或错误代码。示例代码演示了如何设置和使用外部实体解析器函数,使C语言应用程序可以加载外部数据以进行XML解析。
C语言如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录