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("ress 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);
StatusChecker statusChecker = 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也会结束. |
|