2013-08-03 77 views
0

我在我的多線程應用程序中使用了一些System.Threading.Timer(s)(實際上有三個這樣的定時器),但是,儘管它工作得很好,但我感覺我做錯了,並且會消耗不必要的資源。實際上,我在做什麼是這樣的:System.Threading.Timer - 我使用它的權利?

  1. 在我的應用程序的主窗口(WPF窗口,但不認爲它的問題這麼多),我打開三個線程。

  2. 在每一個這三個線程

    ,我初始化和啓動三個定時器

之一

,我使用三種不同的線程來做到這一點的原因是因爲我記得我讀過某處(無法找到位置),當我啓動System.Threading.Timer時,我不能再使用當前線程(例如線程會在Timer啓動時以某種方式停止)。

現在,我測試了下一個簡單的應用程序,並且Timer和啓動它的線程之間似乎沒有衝突。

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    System.Threading.Timer _t1, _t2, _t3; 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     _t1 = new System.Threading.Timer(new TimerCallback(_t1Run), 
          null, TimeSpan.Zero, TimeSpan.FromMilliseconds(15)); 
     _t2 = new System.Threading.Timer(new TimerCallback(_t2Run), 
       null, TimeSpan.Zero, TimeSpan.FromMilliseconds(35)); 
     _t3 = new System.Threading.Timer(new TimerCallback(_t3Run), 
       null, TimeSpan.Zero, TimeSpan.FromMilliseconds(150)); 

     for (int i = 1; i <= 5000; i++) 
     { 
      Console.WriteLine("Writting on main form " + i); 
     } 
    } 

    void _t1Run(object State) 
    { 
     _t1.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); 
     Console.WriteLine("running 1"); 
     _t1.Change(TimeSpan.FromMilliseconds(15), TimeSpan.FromMilliseconds(15)); 
    } 

    void _t2Run(object State) 
    { 
     _t2.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); 
     Console.WriteLine("running 2"); 
     _t2.Change(TimeSpan.FromMilliseconds(35), TimeSpan.FromMilliseconds(35)); 
    } 

    void _t3Run(object State) 
    { 
     _t3.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); 
     Console.WriteLine("running 3"); 
     _t3.Change(TimeSpan.FromMilliseconds(150), TimeSpan.FromMilliseconds(150)); 
    } 

} 

那麼,我可以在主窗口(或我需要單獨的線程)上啓動所有三個定時器嗎?有人可以證實這不會導致問題(因爲在我測試過的應用程序中,它似乎沒有任何問題)?

編輯: 三個定時器有不同的目的,他們兩個確實有一些用戶界面的交互(一個主窗口和其他與二級窗口交互 - 第三做只是一些後臺操作),但我不使用System.Windows.Forms.Timer的原因是計時器進行了大量操作,如果我要在主線程上執行所有這些操作,那麼實際上會阻止所有GUI交互(我在一段時間內調用這些計時器線程100-200毫秒,所以想象...)。 這就是我該怎麼辦,從由定時器稱爲線程的GUI交互的例子:

MainWindow.ThisInstance.TitleLabel.Dispatcher.BeginInvoke((Action)(() => UpdateMainWindow_TimeLabel(TimeLabelValue))); 

回答

4

您應該使用System.Windows.Forms.Timer而不是System.Threading.Timer如果您在計時器回調代碼某種UI元素的交互。

System.Threading.Timer每當經過的時間跨度就會釋放一個線程池線程。但是這會造成Form元素的問題,因爲它們不是線程安全的。使用除專用UI線程之外的線程訪問UI元素可能會產生不需要的結果。

爲了克服這個線程不安全的行爲,應該使用System.Windows.Forms.Timer。 System.Windows.Forms.Timer不創建新的線程或旋轉一個新的線程池線程。它只是在UI線程中運行定時器回調。這樣所有的UI交互都在一個確保線程安全的單線程中執行。

但是,如果您的計時器回調需要大量時間完成,那麼您的UI將凍結,因此System.Windows.Forms.Timer應該只用於非常短的任務。 對於較長的後臺任務,您可以使用System.ComponentModel.BackgroundWorker

+0

最好給你的答案解釋。事實上,這些計時器存在不同的目的。 – Dennis

+0

我編輯並給出了一些解釋。 – TheQuestioner

+0

@nhrobin,好吧,做下一個技巧它告訴我標籤在GUI線程中被更新: 'MainWindow.ThisInstance.TitleLabel.Dispatcher.BeginInvoke((Action)(()=> UpdateMainWindow_TimeLabel(TimeLabelValue)) ); ' 'Private static void UpdateMainWindow_TimeLabel(String TimeLabelValue) Console.WriteLine(「Thread thisCurrentThread.Name」); MainWindowInstance.TimeLabel.Content = TimeLabelValue; }' – TheQuestioner