2012-08-13 30 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(); 
     } 
    } 
} 
相关问题