前言:
而今咱们对“定时器基本原理”大概比较珍视,看官们都需要了解一些“定时器基本原理”的相关文章。那么小编在网上网罗了一些对于“定时器基本原理””的相关文章,希望姐妹们能喜欢,各位老铁们快快来学习一下吧!我最近一直在捣鼓定时器这东西,大家都非常熟悉.Net框架中的这俩家伙,一个是System.Timers.Timer,另一个是System.Windows.Forms.Timer,这俩家伙用起来都是简简单单的,但是性能嘛,就是差点意思,达不到我们的要求。他们的精度受限于系统时钟,一般是15-16毫秒。找了很多资料,都找不到合适的、简洁的高精度定时器类。
偶然之间,我了解到一个叫做winmm.dll的类库。这个类库提供了许多API函数。我查阅了相关的API,结果发现有俩函数叫timeSetEvent和timeKillEvent,这两个函数可以设置和取消计时器事件。这可真是开启了不可思议的操作啊!
现在为你介绍这个家伙怎么搞:
认识winmm.dll库
winmm.dll库是 Windows 操作系统中的一个动态链接库,它主要用于提供多媒体相关的功能支持。winmm.dll 提供了许多 API 函数,这些函数可以用于实现音频、视频处理功能。不过我们这里先不用管这些API。我们重点关注timeSetEvent、timeKillEvent:设置和取消计时器事件。
timeSetEvent 函数
timeSetEvent 函数可以用来创建一个计时器事件,允许程序周期性地接收定时器消息。它的原型如下:
MMRESULT timeSetEvent(UINT uDelay,UINT uResolution,LPTIMECALLBACK lpTimeProc,DWORD_PTR dwUser,UINT fuEvent);`
其中各个参数的含义如下:
uDelay:指定定时器事件的延迟时间,单位为毫秒。uResolution:指定定时器的定时精度,一般为0。lpTimeProc:指向定时器消息处理函数的指针。dwUser:用户定义的数据,会传递给定时器消息处理函数。fuEvent:指定定时器事件的类型,可以是 TIME_ONESHOT 表示一次性事件,也可以是 TIME_PERIODIC 表示周期性事件。
timeSetEvent 函数成功调用后会返回一个标识符,用于标识创建的计时器事件。
timeKillEvent函数
timeKillEvent 函数用于取消由 timeSetEvent 创建的计时器事件,其原型如下:
MMRESULT timeKillEvent(UINT uTimerID);`
其中 uTimerID 是由 timeSetEvent 返回的计时器事件标识符。
这两个函数通常用于实现定时器功能,可以在特定的时间间隔内触发事件或执行特定的操作。可以利用这些函数来实现定时的任务调度、动画效果、定时器监控等功能,是多媒体应用程序中常用的功能之一。
定时器库函数封装
这个类库实现了一个高精度定时器 Timer,提供了定时器的启动、停止和触发事件等功能。使用了多媒体定时器API来实现定时器的功能。其中,timeGetDevCaps函数用于获取系统定时器的能力信息,timeSetEvent函数用于创建定时事件,timeKillEvent函数用于终止定时事件。
Timer类中包含了一些重要的属性和方法。其中,Period属性表示定时器的周期,Resolution属性表示定时器事件触发的最小间隔时间,Mode属性表示定时器的触发模式,IsRunning属性表示定时器是否正在运行。Start方法用于启动定时器,Stop方法用于停止定时器,Dispose方法用于释放资源。同时,还定义了Started、Stopped和Tick三个事件,分别表示定时器启动、停止和触发事件。
另外,该类还支持设置定时器事件处理程序所在的线程,通过SynchronizingObject属性来指定。
总的来说,提供了一个方便易用的高精度定时器,可以用于需要精确计时的场景,如音视频播放、游戏开发等。 类库是完整的代码,可以自己拿去进行测试。
核心逻辑
using System;using System.ComponentModel;using System.Diagnostics;using System.Runtime.InteropServices;namespace PrecisionTimer{ /// <summary> /// 模式 /// </summary> public enum Mode { /// <summary> /// 单次触发模式 /// </summary> OneShot, /// <summary> /// 周期触发模式 /// </summary> Periodic }; [StructLayout(LayoutKind.Sequential)] public struct TimerCaps { /// <summary> /// 最小周期 /// </summary> public int periodMin; /// <summary> /// 最大周期 /// </summary> public int periodMax; } public class TimerException : ApplicationException { public TimerException(string message) : base(message) { } } /// <summary> /// 高精度定时器 Timer /// </summary> public sealed class Timer : IComponent { #region delegate private delegate void TimeProc(int id, int msg, int user, int param1, int param2); private delegate void EventRaiser(EventArgs e); #endregion #region 多媒体定时器API /// <summary> /// 多媒体定时器API:用于获取系统定时器的能力信息 /// </summary> /// <param name="caps"></param> /// <param name="sizeOfTimerCaps"></param> /// <returns></returns> [DllImport("winmm.dll")] private static extern int timeGetDevCaps(ref TimerCaps caps,int sizeOfTimerCaps); /// <summary> /// 多媒体定时器API:创建一个定时事件 /// </summary> /// <param name="delay"></param> /// <param name="resolution"></param> /// <param name="proc"></param> /// <param name="user"></param> /// <param name="mode"></param> /// <returns></returns> [DllImport("winmm.dll")] private static extern int timeSetEvent(int delay, int resolution,TimeProc proc,int user,int mode); /// <summary> /// 多媒体定时器API:终止一个定时事件 /// </summary> /// <param name="id"></param> /// <returns></returns> [DllImport("winmm.dll")] private static extern int timeKillEvent(int id); #endregion #region Private Properties private const int TIMERR_NOERROR = 0; private int timerID; private volatile Mode mode; private volatile int period; private volatile int resolution; private TimeProc timeProcPeriodic; private TimeProc timeProcOneShot; private EventRaiser tickRaiser; private bool running = false; private volatile bool disposed = false; private ISynchronizeInvoke synchronizingObject = null; private ISite site = null; private static TimerCaps caps; #endregion #region Public Events public event EventHandler Started; public event EventHandler Stopped; public event EventHandler Tick; #endregion #region Ctor static Timer() { // Get multimedia timer capabilities. timeGetDevCaps(ref caps, Marshal.SizeOf(caps)); } public Timer(IContainer container) { container.Add(this); Initialize(); } public Timer() { Initialize(); } ~Timer() { if (IsRunning) { // Stop and destroy timer. timeKillEvent(timerID); } } private void Initialize() { this.mode = Mode.Periodic; this.period = Capabilities.periodMin; this.resolution = 1; running = false; timeProcPeriodic = new TimeProc(TimerPeriodicEventCallback); timeProcOneShot = new TimeProc(TimerOneShotEventCallback); tickRaiser = new EventRaiser(OnTick); } #endregion #region 触发事件 public void Start() { if (disposed) { throw new ObjectDisposedException("Timer"); } if (IsRunning) { return; } if (Mode == Mode.Periodic) { timerID = timeSetEvent(Period, Resolution, timeProcPeriodic, 0, (int)Mode); } else { timerID = timeSetEvent(Period, Resolution, timeProcOneShot, 0, (int)Mode); } if (timerID != 0) { running = true; if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) { SynchronizingObject.BeginInvoke( new EventRaiser(OnStarted), new object[] { EventArgs.Empty }); } else { OnStarted(EventArgs.Empty); } } else { throw new TimerException("Unable to start timer."); } } public void Stop() { if (disposed) { throw new ObjectDisposedException("Timer"); } if (!running) { return; } int result = timeKillEvent(timerID); Debug.Assert(result == TIMERR_NOERROR); running = false; if (SynchronizingObject != null && SynchronizingObject.InvokeRequired) { SynchronizingObject.BeginInvoke( new EventRaiser(OnStopped), new object[] { EventArgs.Empty }); } else { OnStopped(EventArgs.Empty); } } public void Dispose() { if (disposed) { return; } if (IsRunning) { Stop(); } disposed = true; OnDisposed(EventArgs.Empty); } private void TimerPeriodicEventCallback(int id, int msg, int user, int param1, int param2) { if (synchronizingObject != null) { synchronizingObject.BeginInvoke(tickRaiser, new object[] { EventArgs.Empty }); } else { OnTick(EventArgs.Empty); } } private void TimerOneShotEventCallback(int id, int msg, int user, int param1, int param2) { if (synchronizingObject != null) { synchronizingObject.BeginInvoke(tickRaiser, new object[] { EventArgs.Empty }); Stop(); } else { OnTick(EventArgs.Empty); Stop(); } } // 触发 Disposed 事件. private void OnDisposed(EventArgs e) { EventHandler handler = Disposed; if (handler != null) { handler(this, e); } } // 触发 Started 事件. private void OnStarted(EventArgs e) { EventHandler handler = Started; if (handler != null) { handler(this, e); } } // 触发 Stopped 事件. private void OnStopped(EventArgs e) { EventHandler handler = Stopped; if (handler != null) { handler(this, e); } } // 触发 Tick 事件. private void OnTick(EventArgs e) { EventHandler handler = Tick; if (handler != null) { handler(this, e); } } /// <summary> /// 获取或设置用于调度事件处理程序调用的对象。 /// </summary> public ISynchronizeInvoke SynchronizingObject { get { #region Require if (disposed) { throw new ObjectDisposedException("Timer"); } #endregion return synchronizingObject; } set { #region Require if (disposed) { throw new ObjectDisposedException("Timer"); } #endregion synchronizingObject = value; } } #endregion #region Public Properties /// <summary> /// 周期 /// </summary> public int Period { get { #region Require if (disposed) { throw new ObjectDisposedException("Timer"); } #endregion return period; } set { #region Require if (disposed) { throw new ObjectDisposedException("Timer"); } else if (value < Capabilities.periodMin || value > Capabilities.periodMax) { throw new ArgumentOutOfRangeException("Period", value, "Multimedia Timer period out of range."); } #endregion period = value; if (IsRunning) { Stop(); Start(); } } } /// <summary> /// 定时器事件触发的最小间隔时间 /// </summary> public int Resolution { get { if (disposed) { throw new ObjectDisposedException("Timer"); } return resolution; } set { if (disposed) { throw new ObjectDisposedException("Timer"); } else if (value < 0) { throw new ArgumentOutOfRangeException("Resolution", value,"timer resolution out of range."); } resolution = value; if (IsRunning) { Stop(); Start(); } } } /// <summary> /// 触发模式 /// </summary> public Mode Mode { get { if (disposed) { throw new ObjectDisposedException("Timer"); } return mode; } set { if (disposed) { throw new ObjectDisposedException("Timer"); } mode = value; if (IsRunning) { Stop(); Start(); } } } /// <summary> /// 是否正则运行 /// </summary> public bool IsRunning { get { return running; } } /// <summary> /// 获取定时器的能力信息 /// </summary> public static TimerCaps Capabilities { get { return caps; } } #endregion #region IComponent public event System.EventHandler Disposed; public ISite Site { get { return site; } set { site = value; } } #endregion }}测试代码
public partial class MainWindow : Window{ private PrecisionTimer.Timer mTimer = null; private DateTime lastTimerTick = DateTime.Now; private int index = 0; public MainWindow() { InitializeComponent(); } private void btnLoad_Click(object sender, RoutedEventArgs e) { mTimer = new PrecisionTimer.Timer(); mTimer.Period = 20; mTimer.Tick += new EventHandler(OnTimerTick); lastTimerTick = DateTime.Now; mTimer.Start(); } private void OnTimerTick(object sender, EventArgs e) { index++; lastTimerTick = DateTime.Now; Trace.WriteLine($"{lastTimerTick.ToString("HH:mm:ss ffff")} ThreadId:{Thread.CurrentThread.ManagedThreadId.ToString()},index = {index}"); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); mTimer.Stop(); mTimer.Dispose(); } }}输出结果
19:20:20 3015 ThreadId:7,index = 119:20:20 3167 ThreadId:7,index = 219:20:20 3368 ThreadId:7,index = 319:20:20 3569 ThreadId:7,index = 419:20:20 3770 ThreadId:7,index = 519:20:20 3970 ThreadId:7,index = 619:20:20 4170 ThreadId:7,index = 719:20:20 4367 ThreadId:7,index = 819:20:20 4567 ThreadId:7,index = 919:20:20 4767 ThreadId:7,index = 10和原生Timer对比
与Windows Forms自带的Timer控件相比,该Timer类有一些区别和优势:
精度更高:PrecisionTimer使用了Windows多媒体定时器(Multimedia Timer),可以提供更高的计时精度,最小精度为1毫秒。而Windows Forms自带的Timer控件的精度受系统时钟的限制,一般为15-16毫秒。可调节的周期和分辨率:PrecisionTimer允许用户设置定时器的周期和分辨率,可以根据具体需求进行调整。而Windows Forms自带的Timer控件的周期固定为1000毫秒(1秒),无法更改。支持多种模式:PrecisionTimer支持两种模式:OneShot(单次触发)和Periodic(周期性触发),可以根据需要选择不同的模式。而Windows Forms自带的Timer控件仅支持周期性触发。可以选择事件处理线程:PrecisionTimer可以通过SynchronizingObject属性指定事件处理的线程,从而避免在多线程环境下引发线程冲突的问题。而Windows Forms自带的Timer控件的Tick事件总是在UI线程上触发。更灵活的事件处理:PrecisionTimer定义了Started、Stopped、Tick和Disposed事件,可以方便地对定时器的状态变化进行监听和处理。而Windows Forms自带的Timer控件仅提供Tick事件。
如果你有兴趣,可以试试,欢迎评论留言一起交流。
#挑战30天在头条写日记#
#自律学习计划#
#实话实说#
#定时器#
标签: #定时器基本原理 #定时器基本原理图解视频