2011-10-25 64 views
16

我試圖瞭解什麼時候System.Timers.Timer引發流逝的事件,是否在獨立的線程中引發?下面System.Timers.Timer是否在獨立線程中運行?

我的例子似乎表明,三個定時器在自己的線程獨立運行:基於您的代碼

class Program 
{ 
    static System.Timers.Timer timer = new System.Timers.Timer(); 
    static System.Timers.Timer timer2 = new System.Timers.Timer(); 
    static System.Timers.Timer timer3 = new System.Timers.Timer(); 

    static void Main(string[] args) 
    { 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(
      timer_Elapsed); 
     timer2.Elapsed += new System.Timers.ElapsedEventHandler(
      timer2_Elapsed); 
     timer3.Elapsed += new System.Timers.ElapsedEventHandler(
      timer3_Elapsed); 

     timer.Interval = 1000; 
     timer2.Interval = 1000; 
     timer3.Interval = 1000; 

     timer.Start(); 
     timer2.Start(); 
     timer3.Start(); 

     Console.WriteLine("Press \'q\' to quit the sample."); 
     while (Console.Read() != 'q') ; 
    } 

    static void timer3_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     timer3.Stop(); 
     Console.WriteLine("Timer 3 Hit...");    
     timer3.Start(); 
    } 

    static void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     timer2.Stop(); 
     Console.WriteLine("Timer 2 Hit..."); 
     Thread.Sleep(2000); 
     timer2.Start(); 
    } 

    static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     timer.Stop(); 
     Console.WriteLine("Timer 1 Hit..."); 
     Thread.Sleep(10000); 
     timer.Start(); 
    } 
} 

enter image description here

+1

是的,定時器是線程化的。 – qJake

+0

是的,他們運行在不同的線程。 –

回答

20

按照MSDN上System.Timers.TimerElapsed事件觸發它被稱爲在系統線程池中的線程:

如果SynchronizingObject的屬性是沒什麼,經過的事件是在一個線程池升起線。如果處理Elapsed事件的持續時間比Interval長,則可能會在另一個ThreadPool線程上再次引發該事件。在這種情況下,事件處理程序應該是可重入的。

由於SynchronizingObject默認值爲空,那麼所有你過去的事件將是對線程池處理。所以,它取決於線程池的完整性,如果有空閒線程,那麼每個經過的事件很可能在單獨的線程上併發運行。但是,如果由於某種原因,系統線程池已經被完全使用,那麼可能已過期的事件將按照它們的計劃進行序列化。

重點是:「它要看」。也就是說,只要池中有空閒線程,它們將被允許並行運行。

參考:MSDN on System.Timers.Timer

+0

所有的答案都是正確的,但我覺得ThreadPool是這裏的關鍵組件。 – newbie

4

他們必須的,因爲Thread.Sleep是一個阻塞調用。如果他們在同一個線程上運行,其他定時器都不會觸發。你可以輸出System.Threading.Thread.CurrentThread.ManagedThreadId以確認。

2

是的,每一個經過的被調用時,回調是在自己的線程解僱。

此外,沒有什麼能夠阻止一個Elapsed事件處理程序在前一個事件處理程序完成之前觸發。例如,如果您的計時器每500毫秒觸發一次,但Elapsed事件處理程序代碼需要2秒才能完成,則Elapsed代碼可以訪問相同的資源(非線程安全的對象,文件等)。

4

這很複雜。 documentation指出以下內容:

基於服務器的Timer專爲在多線程環境中與工作線程一起使用而設計。服務器定時器可以在線程之間移動以處理引發的Elapsed事件,從而比按時提升事件的Windows定時器更準確。

,然後這樣的:

如果物業對於SynchronizingObject爲null,經過的事件引發的一個線程池線程。如果處理Elapsed事件的持續時間比Interval長,則可能會在另一個ThreadPool線程上再次引發該事件。在這種情況下,事件處理程序應該是可重入的。

,然後將此:

如果使用計時器與用戶界面元件,諸如形式或控制,無需將所述計時器的用戶界面元素上,分配的形式或控制包含定時器到SynchronizingObject屬性,以便將事件封送到用戶界面線程。

所以,你的問題沒有簡單的答案,「它是在獨立的線程中提出的嗎?」這取決於很多事情。

相關問題