C#定时器

1.单线程的定时器存在很多问题,定时器只是定时把消息WM_TIMER访到线程的消息队列里,但并不保证消息会立即被响应,如果碰巧系统比较忙,消息可能会在队列里放一段时间才被响应,这样会造成本来应该间隔一段时间发生的消息连续发生了。
2. 。NET FrameWork带来了新的解决方案
 Server TimersSystem.Timers.Timer基于服务器的计时器,位于"工具箱"的“组件”选项卡上
 Thread TimersSystem.Threading.Timer在编程时使用的线程计时器
 Windows TimersSystem.Windows.Forms.Timer基于 Windows 的标准计时器,"工具箱"的"Windows 窗体"选项卡上;
  • 区别a
    Windows Timers 提供了和WinAPI一样的Timer 基于消息,仍然是单线程
    其他两个是是基于线程池的Thread Pool【最大好处,产生的时间准确均匀】
  • 区别b
    Server Timers  和 Thread Timers 的不同在于ServerTimers 是基于事件的,Thread Timers是基于回调函数

Thread Timer是一个轻量级的方便使用,但也要注意一些问题,由于是多线程定时器,就会出现如果一个Timer处理没有完成,到了时间下一个照样会发生,导致严重错误,对付重入问题,通常的办法是加锁,但对于Timer不能简单的这样处理。

使用Timer来处于的事情,要注意:

首先Timer处理里本来就不应该做太需要时间的事情,或者花费时间无法估计的事情,比同远方的服务器建立一个网络连接,这样的做法尽量避免
如果实在无法避免,那么要评估Timer处理超时是否经常发生,如果是很少出现,那么可以用lock(Object)的方法来防止重入
如果这种情况经常出现呢?那就要用另外的方法来防止重入了

我们可以设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃执行

static  int inTimer = 0;
public static void threadTimerCallback(Object obj)
{
     if ( inTiemr == 0 )
    {
         inTimer = 1;        

         Console.WriteLine("Time:{0}, /tThread ID:{1}", DateTime.Now, Thread.CurrentThread.GetHashCode());
         Thread.Sleep(2000);

         inTimer = 0;
      }
}

但是在多线程下给inTimer赋值不够安全,还好Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法

 static int inTimer = 0;
 public static void threadTimerCallback(Object obj)
 {
       if ( Interlocked.Exchange(ref inTimer, 1) == 0 )
      {
           Console.WriteLine("Time:{0}, /tThread ID:{1}", DateTime.Now, Thread.CurrentThread.GetHashCode());
           Thread.Sleep(250);

           Interlocked.Exchange(ref inTimer, 0);
      }
 }

====试验=======================================================
1.ThreadTimer = new System.Threading.Timer(new TimerCallBack(onTime),this,0,1000)
 [- 参数 -]
  a.回调方法,
  b.回调方法中使用信息的对象,
  c.表示在 callback 参数调用它的方法之前延迟的时间量。指定 -1 毫秒以防止启动计时器。指定零 (0) 以立即启动计时器。
  d.在调用 callback 所引用的方法之间的时间间隔。指定 -1 毫秒可以禁用定期终止
 
2.

来源:(http://blog.sina.com.cn/s/blog_4b4c258701000649.html) - C#定时器_半糖主义_新浪博客

BaseTimeHandler 自定义一个事件
 
void OnTime(Object State)
{
   Control ctl = State as Form1;
   
   if ( ctl != null && BaseTimeHandler != null)
   {
    if ( ctl.IsHandleCreated )
    {
     DateTime dt = DateTime.Now; 
     String DateString = dt.ToString("yyyy/MM/dd");
     String TimeString = dt.ToString("HH:mm:ss");
   
     string[] args = new string[]{DateString,TimeString};    
     try
     {
      //如果在不同线程中
      if ( ctl.InvokeRequired )
       ctl.Invoke(BaseTimeHandler,args);
      else
       BaseTimeHandler(DateString,TimeString);
     }
     catch(Exception e)
     { }
    }
   }   
}
<think> 我们在讨论C#中的定时器,根据用户的需求,我们需要介绍C#定时器的使用方法、实现原理等。参考提供的引用内容,我们可以总结出三种常见的定时器实现方法: 1. 使用System.Timers.Timer类 2. 使用System.Threading.Timer类(引用[2]中提到了Threading.Timer) 3. 使用System.Windows.Forms.Timer(在WinForms中使用,如引用[3]中的例子)或者使用System.Threading.Tasks.Task(引用[1]中提到的第三种方法) 但是,请注意引用[1]中提到的三种方法是: 1. 使用Timer类(可能指System.Timers.TimerSystem.Threading.Timer) 2. 使用Thread和Sleep方法 3. 使用Task和Delay方法 因此,我们可以将这些方法归纳为: 1. System.Timers.Timer:基于服务器的计时器,适用于多线程环境,在Elapsed事件中执行操作。 2. System.Threading.Timer线程池中的计时器,使用回调方法。 3. System.Windows.Forms.TimerWindows窗体计时器,用于UI操作,事件在UI线程执行。 4. 使用Thread和Sleep:通过线程休眠实现定时操作(但这种方法会阻塞线程,一般建议在主线程使用)。 5. 使用Task和Delay:基于异步任务的延迟,会阻塞线程,适用于异步编程。 然而,根据引用内容,我们主要关注前三种(因为它们更常用且更规范),并补充Task.Delay的方法。 下面我们将详细介绍几种常用的定时器: 一、System.Timers.Timer 这是一个基于服务器的计时器,它使用系统时间间隔来触发事件(Elapsed事件)。它适用于多线程环境,因为事件处理程序会在ThreadPool线程上运行。 二、System.Threading.Timer 这是一个轻量级的计时器,它使用回调方法,并由线程线程执行。它没有事件,而是直接指定回调方法。 三、System.Windows.Forms.Timer 这是一个基于UI的计时器,它的事件处理程序在UI线程上执行,因此可以直接更新UI控件。但是,它精度较低,且如果UI线程忙,则事件会被延迟。 四、使用Task.Delay 在异步编程中,我们可以使用Task.Delay方法来创建一个异步的等待,然后执行周期性操作。 为了清晰,我们分别给出每种方法的示例代码(部分代码参考引用内容): 1. System.Timers.Timer(引用[2]中的例子): 注意:需要引用System.Timers命名空间。 2. System.Threading.Timer(引用[1]中提到的第二种方法,但引用[1]并没有给出代码,我们补充): 注意:需要引用System.Threading命名空间。 3. System.Windows.Forms.Timer(引用[3]中的例子): 注意:这个定时器只能用于Windows窗体应用程序。 4. 使用Task.Delay(引用[1]中提到的第三种方法): 注意:需要引用System.Threading.Tasks命名空间。 此外,我们还需要讨论一下定时器的实现原理。定时器的核心原理是使用系统时钟中断或者高精度计时器(如多媒体计时器)来计时,当达到设定的时间间隔后,触发回调或事件。 由于用户要求生成相关问题,我们在最后添加相关问题。 注意:根据系统指令,数学公式使用$...$,但本问题中没有数学公式,所以主要关注代码和文字描述。 下面按照要求组织回答: </think> ### C#定时器的使用与实现 C#提供了多种定时器实现方式,每种适用于同场景。以下是主要定时器的使用方法及实现原理: #### 一、常用定时器类型 1. **System.Timers.Timer** 基于线程池的服务器级定时器,适用于多线程环境,精度较高(约10-30ms)。 ```csharp using System.Timers; public class TimerExample { private static Timer timer; public static void Main() { timer = new Timer(1000); // 1秒间隔 timer.Elapsed += OnTimedEvent; // 绑定事件 timer.AutoReset = true; // 自动重置 timer.Enabled = true; // 启动计时器 Console.ReadKey(); timer.Stop(); // 停止计时器 timer.Dispose(); } private static void OnTimedEvent(object source, ElapsedEventArgs e) { Console.WriteLine($"触发时间: {e.SignalTime:HH:mm:ss.fff}"); } } ``` 2. **System.Threading.Timer** 轻量级线程定时器,适用于后台任务,需手动管理生命周期。 ```csharp using System.Threading; public class ThreadingTimer { private static Timer timer; public static void Main() { // 参数:回调方法,状态对象,延迟时间,间隔时间 timer = new Timer(TimerCallback, null, 0, 1000); Console.ReadKey(); timer.Dispose(); // 释放资源 } private static void TimerCallback(object state) { Console.WriteLine($"当前时间: {DateTime.Now:HH:mm:ss}"); } } ``` 3. **System.Windows.Forms.Timer** UI线程专用定时器(WinForms),事件在UI线程执行,可直接更新控件。 ```csharp // 窗体代码中 private Timer timer = new Timer(); private int colorIndex = 0; private Color[] colors = { Color.Red, Color.Blue, Color.Cyan }; private void InitTimer() { timer.Interval = 2000; // 2秒间隔 timer.Tick += Timer_Tick; timer.Start(); } private void Timer_Tick(object sender, EventArgs e) { this.BackColor = colors[colorIndex]; colorIndex = (colorIndex + 1) % colors.Length; // 循环切换颜色 } ``` #### 二、异步定时方案 4. **Task.Delay + async/await** 非阻塞式异步定时,适合异步编程模型。 ```csharp public async Task RunPeriodicTaskAsync() { while (true) { await Task.Delay(1000); // 等待1秒 Console.WriteLine($"异步执行: {DateTime.Now.Second}"); } } ``` #### 三、实现原理与特性对比 | 特性 | System.Timers.Timer | System.Threading.Timer | Windows.Forms.Timer | |---------------------|---------------------|------------------------|---------------------| | **执行线程** | 线程池 | 线程池 | UI线程 | | **精度范围** | 10-30ms | 10-30ms | ~55ms | | **适用场景** | 服务/后台任务 | 后台任务 | UI更新 | | **跨线程访问控件** | 需Invoke | 需Invoke | 直接支持 | | **资源消耗** | 中等 | 低 | 低 | **核心原理**:所有定时器均依赖于Windows系统计时器内核对象,通过时间片轮询触发回调。高精度定时器(如多媒体计时器)可实现1ms精度,但常规定时器受限于系统时钟分辨率(默认15.6ms)[^1]。 #### 四、使用注意事项 1. 资源释放:实现`IDisposable`的定时器需手动调用`Dispose()` 2. 线程安全:非UI定时器更新控件需通过`Control.Invoke` 3. 精度限制:避免在定时器中执行长时间操作 4. 生命周期管理:防止因定时器持续引用导致内存泄漏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值