2012-08-13 35 views
9

如何在其回調方法中停止System.Threading.Timer。我引用了MSDN,但找不到任何有用的東西。請幫忙。如何在回調方法中停止System.Threading.Timer

+0

也http://stackoverflow.com/questions/6379541/reliably-stop-system-threading-timer – 2012-08-13 16:37:03

+0

是的,我已經檢查了它 – Proceso 2012-08-13 18:12:29

回答

4
timer.Change(Timeout.Infinite, Timeout.Infinite); 
+0

更好的處理是正確的,然後看看。 – usr 2012-08-13 16:46:04

+1

如果我想稍後重新啓動,該怎麼辦? – Volma 2012-08-13 17:38:55

1

您可以直接致電myTimer.Change(Timeout.Infinite, Timeout.Infinite)

從技術上講,只有第一個參數(dueTime)需要指定爲Timeout.Infinite以使計時器停止。

欲瞭解更多信息,請參閱Timer.Change Method

+0

最好將它放置,因爲它能更好地捕捉語義。它可能也會更快。 – usr 2012-08-13 16:47:05

+0

這取決於用戶是否永久停止計時器,或者如果他們暫停一段時間並可能在稍後重新啓動計時器。如果使用'.Dispose()'來簡單地暫停計時器,那麼如果要重新啓動計時器,或者只是更改dueTime或句點,就會遇到問題。在這些情況下,使用'timer.Change()'更安全(更簡單)。 – 2012-08-13 17:19:33

2

試試這個:

如果你願意,你可以讓計時器繼續射擊回調方法,包括以下

private void CreatorLoop(object state) 
{ 
    if (Monitor.TryEnter(lockObject) 
    { 
    try 
    { 
     // Work here 
    } 
    finally 
    { 
     Monitor.Exit(lockObject); 
    } 
    } 
} 

退房這個環節太代碼:

Stopping timer in its callback method

14

首先,回調方法必須具有定時器實例的範圍。

那麼簡單的咒語

timerInstance.Change(Timeout.Infinite , Timeout.Infinite) ; 

將關閉計時器。有可能定時器可能會在更改後再次調用回調方法,我相信這取決於它所處的狀態。

+0

因爲它能更好地捕捉語義,所以最好放置它。它可能也會更快。 – usr 2012-08-13 16:46:43

+3

取決於計時器是要在以後重新啓動還是完成。 OP指定她想「停止定時器」,而不是「破壞定時器」。定時器實例及其生命週期是其創建者的責任。 – 2012-08-13 16:50:45

+0

與該解決方案這是問題,線程不會立即停止。 – Proceso 2012-08-13 18:13:11

0

我發現改變(Timeout.Infinite,Timeout.Infinite)的方式很麻煩, t相當可靠,並切換到AutoReset = false的System.Timers.Timer。

0

Timer的問題在於它可能會在處理其所有者類後調用。以下實現通過使用Timer初始值設定項的狀態對象爲我工作。消耗之前,堆不會移除該對象。這是我優雅地清理計時器回調的唯一方法。

using System; 
using System.Threading; 

namespace TimerDispose 
{ 
    /// <summary> 
    /// A timer-containing class that can be disposed safely by allowing the timer 
    /// callback that it must exit/cancel its processes 
    /// </summary> 
    class TimerOwner : IDisposable 
    { 
     const int dueTime = 5 * 100;  //halve a second 
     const int timerPeriod = 1 * 1000; //Repeat timer every one second (make it Timeout.Inifinite if no repeating required) 

     private TimerCanceller timerCanceller = new TimerCanceller(); 

     private Timer timer; 

     public TimerOwner() 
     { 
      timerInit(dueTime); 
     } 

     byte[] dummy = new byte[100000]; 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="dueTime">Pass dueTime for the first time, then TimerPeriod will be passed automatically</param> 
     private void timerInit(int dueTime) 
     { 

      timer = new Timer(timerCallback, 
       timerCanceller,  //this is the trick, it will be kept in the heap until it is consumed by the callback 
       dueTime, 
       Timeout.Infinite 
      ); 

     } 

     private void timerCallback(object state) 
     { 
      try 
      { 
       //First exit if the timer was stoped before calling callback. This info is saved in state 
       var canceller = (TimerCanceller)state; 
       if (canceller.Cancelled) 
       { 
        return; // 
       } 

       //Your logic goes here. Please take care ! the callback might have already been called before stoping the timer 
       //and we might be already here after intending of stoping the timer. In most cases it is fine but try not to consume 
       //an object of this class because it might be already disposed. If you have to do that, hopefully it will be catched by 
       //the ObjectDisposedException below 




       dummy[1] = 50; //just messing up with the object after it might be disposed/nulled 

       //Yes, we need to check again. Read above note 
       if (canceller.Cancelled) 
       { 
        //Dispose any resource that might have been initialized above 
        return; // 
       } 

       if (timerPeriod != Timeout.Infinite) 
       { 
        timerInit(timerPeriod); 
       } 
      } 
      catch (ObjectDisposedException ex) 
      { 
       Console.WriteLine("A disposed object accessed"); 
      } 
      catch (NullReferenceException ex) 
      { 
       Console.WriteLine("A nulled object accessed"); 
      } 
      catch (Exception ex) 
      { 

      } 
     } 

     public void releaseTimer() 
     { 
      timerCanceller.Cancelled = true; 
      timer.Change(Timeout.Infinite, Timeout.Infinite); 
      timer.Dispose(); 
     } 

     public void Dispose() 
     { 
      releaseTimer(); 
      dummy = null; //for testing 
      GC.SuppressFinalize(this); 
     } 
    } 

    class TimerCanceller 
    { 
     public bool Cancelled = false; 
    } 


    /// <summary> 
    /// Testing the implementation 
    /// </summary> 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var list = new System.Collections.Generic.List<TimerOwner>(); 
      Console.WriteLine("Started initializing"); 
      for (int i = 0; i < 500000; i++) 
      { 
       list.Add(new TimerOwner()); 
      } 

      Console.WriteLine("Started releasing"); 
      foreach (var item in list) 
      { 
       item.Dispose(); 
      } 

      Console.WriteLine("Press any key to exit"); 
      Console.ReadKey(); 
     } 
    } 
} 
相關問題