C#的timer類


在C#里關於定時器類就有3個
1.定義在System.Windows.Forms里
2.定義在System.Threading.Timer類里
3.定義在System.Timers.Timer類里
System.Windows.Forms.Timer是應用於WinForm中的,它是通過Windows消息機制實現的,類似於VB或Delphi中的Timer控件,內部使用API SetTimer實現的。它的主要缺點是計時不精確,而且必須有消息循環,Console Application(控制台應用程序)無法使用。

System.Timers.Timer和System.Threading.Timer非常類似,它們是通過.NET Thread Pool實現的,輕量,計時精確,對應用程序、消息沒有特別的要求。System.Timers.Timer還可以應用於WinForm,完全取代上面的Timer控件。它們的缺點是不支持直接的拖放,需要手工編碼。
例:
使用System.Timers.Timer類
System.Timers.Timer t = new System.Timers.Timer(1000);//實例化Timer類,設置間隔時間為10000毫秒;

//或者是實例化時不傳遞參數.通過 myTimer.Interval=1000; 來設置間隔時間;
t.Elapsed += new System.Timers.ElapsedEventHandler(theout);//到達時間的時候執行事件;
t.AutoReset = true;//設置是執行一次(false)還是一直執行(true);
t.Enabled = true;//是否執行System.Timers.Timer.Elapsed事件;
public void theout(object source, System.Timers.ElapsedEventArgs e)
{
MessageBox.Show( "OK! ");
}


關於定時器
定時器是個很有意思的東西,它很有用,但我認為這不是現代計算機的結構所擅長的事情。
計算機適合做那些很大量的簡單重復工作,或者根據請求做出回應。
DOS時代是沒有進程線程等概念的,那時候要想做到定時真是有些麻煩
通常的做法是死循環不斷監測時間,發現時間到了就做特定的事情
當然你可以用delay,來指定等待多長時間,但是如果你一邊要響應用戶的操作,比如輸入,一邊要定時做些
事情就是一件麻煩的事了
當然有些人可以這樣做,截取系統的時鍾中斷(我忘了中斷號是多少了),每秒鍾有18.2次
當這些做法都不是很優雅。但DOS時代只能這樣湊合着了
Windows是個偉大的進步,系統提供了Timer支持,但是問題是這個定時器並不准時而且有時候根本不能用。
Win32 API中有個SetTimer函數,可以為一個窗口創建一個定時器,這個定時器會定時產生消息WM_TIMER也可以調用
指定的回調函數,其實這都是一樣的,因為都是單線程的。
單線程的定時器會有很多問題,首先是不准時,定時器只是定時把消息WM_TIMER訪到線程的消息隊列里,但是並不保證消息會立刻被響應,如果
碰巧系統比較忙,那么消息可能會在隊列里放一端時間才被響應,還會造成本來應該間隔一段時間發生的消息響應連續發生了
解決方法通常是
OnTimer(...)
{
//Timer process.....

MSG msg;
While(PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE));
}
在當前Timer處理中,把消息隊列里的WM_TIMER消息,清除掉。
更糟的是如果你不去調用GetMessage,那么就不會有Timer發生了。
這個問題直到win xp都沒什么改變,似乎微軟並不打算在Win32 API中解決這個問題了。
.NET Framework為我們帶來了新的解決方案
.NET Framework提供三種Timer
Server Timers System.Timers.Timer
Thread Timers System.Threading.Timer
Windows Timers System.Windows.Forms.Timer
其中Windows Timers只是提供了和WinAPI 一樣的Timer,仍然是基於消息,仍然是單線程
其它兩個就不同了,他們是基於線程池的Thread Pool,這樣最大的好處在於,產生的時間間隔准確均勻。
Server Timers 和 Thread Timers 的不同在於ServerTimers 是基於事件的,Thread Timers是基於回調函數, 比較輕量級方便易用。
但是這樣的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);
}
}


正確的選擇使用.NET中的三個Timer
Timer這個類在.NET的類庫中有三個:

1)System.Threading.Timer

是一個使用回調方法的計時器,而且由線程池線程服務,簡單且對資源要求不高。

2)System.Windows.Forms.Timer

這是一個必須和Windows窗體一起使用的Timer。

3)System.Timers.Timer

基於服務器計時器功能的Timer,根據服務器系統時間進行運行的Timer。如果需要寫Windows Services的話可以使用這個Timer來進行一

些需要在一定間隔時間進行某項操作的環境下使用。
它使您能夠指定在應用程序中引發 Elapsed 事件的周期性間隔。然后可以操控此事件以提供定期處理。例如,假設您有一台關鍵性服務

器,必須每周 7 天、每天 24 小時都保持運行。可以創建一個使用 Timer 的服務,以定期檢查服務器並確保系統開啟並在運行。如果系統不

響應,則該服務可以嘗試重新啟動服務器或通知管理員。基於服務器的 Timer 是為在多線程環境中用於輔助線程而設計的。服務器計時器可

以在線程間移動來處理引發的 Elapsed 事件,這樣就可以比 Windows 計時器更精確地按時引發事件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM