Carl 发表于 2009-12-9 15:58:00

.net 中的Timer3胞胎

Post by "aloneplayer", 2006-10-12, 12:38
-----------------------------------------------------
.net 中的Timer3胞胎
Win32平台上有两种线程:UI线程和工作线程,UI线程大多数时间是空闲的,它实际上是一个形如
while (GetMessage (&msg))
   {
ProcessMessage (&msg) ;
    }
的循环,如果这个UI线程的消息队列中有消息, UI线程就会取出这个message并处理.
工作线程没有message loop,主要用来在后台处理事务.


System.Windows.Forms.Timer Control
    windows timer, 其历史可以追溯到vb 1.0, 主要是为了方便windows froms程序的编写.
    有一个Interval属性
    为使用UI线程进行事务处理的单线程环境设计,依赖于os的timer message,精度较差,
    操作可以在UI线程中进行,也可以在别的线程中进行.
    注意windows不会向消息队列中放入多个WM_TIMER消息,而是将多个WM_TIMER消息合并成
    一个消息(和WM_PAINT类似),如果设定WM_TIMER消息的间隔为1秒,而消息处理函数的执行
    时间超过1秒,在消息3处理函数的执行期间程序不会收到WM_TIMER消息.

System.Timers.Timer component
    有一个Interval属性
    针对server的多线程环境进行了了优化,采用了和System.Windows.Forms.Timer不同的架构.
    值得注意的是System.Timers.Timer的SynchronizingObject属性.如果这个属性为null,处理
    Elapsed event由线程池中的线程触发,即Elapsed event的处理函数将运行在系统线程池的
    线程中,如果 SynchronizingObject属性被设置为一个Windows Forms component, 那么
    Elapsed event的处理函数将运行在生成component的那个线程中,通常情况下,这个线程就
    是UI线程.
    如果处理Elapsed event的方法的执行时间大于Interval属性的值,又会有一个线程池中的线
    程激发Elapsed event,Elapsed event的处理函数将会被重入.
   
    using System;
    using System.Timers;
   
    public class Timer1
    {
      public static void Main()
      {
            // Normally, the timer is declared at the class level, so
            // that it doesn't go out of scope when the method ends.
            // In this example, the timer is needed only while Main
            // is executing. However, KeepAlive must be used at the
            // end of Main, to prevent the JIT compiler from allowing
            // aggressive garbage collection to occur before Main
            // ends.
            System.Timers.Timer aTimer = new System.Timers.Timer();
   
            // Hook up the Elapsed event for the timer.
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
   
            // Set the Interval to 2 seconds (2000 milliseconds).
            aTimer.Interval = 2000;
            aTimer.Enabled = true;
   
            Console.WriteLine("Press the Enter key to exit the program.");
            Console.ReadLine();
   
            // Keep the timer alive until the end of Main!
            GC.KeepAlive(aTimer);
      }
   
      // Specify what you want to happen when the Elapsed event is
      // raised.
      private static void OnTimedEvent(object source, ElapsedEventArgs e)
      {
            Console.WriteLine("Hello World!");
      }
    }
    注意!由于Elapsed event由线程池中的线程出发,存在着这样的可能:event 的处理函数
    正在执行,而另一个线程池中的线程调用的Timer.Stop(),这将导致在Timer.Stop()调用后
    Elapsed event仍可被触发.使用Interlocked.CompareExchange()可以避免这种情况.
   
System.Threading.Timer class
在代码中使用,不依赖于os 的timer
使用 TimerCallback delegate 来指定需要执行的函数,这个函数将执行在线程池
的线程中,而不是生成System.Threading.Timer的线程中.
在timer生成后,可以使用System.Threading.Timer.Change()来重新定义timer的
等待时间和执行间隔时间.
注意,如果使用了System.Threading.Timer,就要保持对Timer的引用,否则,Timer将会被
GC回收,使用Timer.Dispose()可以释放Timer所占用的资源.
由于callback函数由线程池中的线程执行,如果timer的interval值小于callback函数的
执行时间,callback函数会被多个线程执行.如果线程池中的线程被用光,callback函数
会排队等待,不能如期执行.

//----
using System;
    using System.Threading;
   
    class TimerExample
    {
      static void Main()
      {
            //信号量,false参数用来设置信号量的初始状态为non-signaled
            AutoResetEvent autoEvent   = new AutoResetEvent(false);
            StatusCheckerstatusChecker = new StatusChecker(10);
   
            // Create the delegate that invokes methods for the timer.
            TimerCallback timerDelegate =new TimerCallback(statusChecker.CheckStatus);
   
            // Create a timer that signals the delegate to invoke
            // CheckStatus after one second, and every 1/4 second
            // thereafter.
            Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, 250);
   
            // When autoEvent signals, change the period to every 1/2 second.
            autoEvent.WaitOne(5000, false);
            stateTimer.Change(0, 500);
         
            // When autoEvent signals the second time, dispose of the timer.
            autoEvent.WaitOne(5000, false);
            stateTimer.Dispose();
      }
    }
   
    class StatusChecker
    {
      int invokeCount, maxCount;
   
      public StatusChecker(int count)
      {
            invokeCount= 0;
            maxCount = count;
      }
   
      // This method is called by the timer delegate.
      public void CheckStatus(Object stateInfo)
      {
            AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
            Console.WriteLine("{0} Checking status {1,2}.",
                DateTime.Now.ToString("h:mm:ss.fff"),
                (++invokeCount).ToString());
   
            if(invokeCount == maxCount)
            {
                // Reset the counter and signal Main.
                invokeCount= 0;
                autoEvent.Set();
            }
      }
    }

ThreadPool
    线程池中的线程为后台线程,其IsBackgroud为true, 当application的所有前台线程执行
    完毕后,就算是线程池中的线程仍在执行,application也会结束.
页: [1]
查看完整版本: .net 中的Timer3胞胎