【问题标题】:How to stop System.Threading.Timer in callback method如何在回调方法中停止 System.Threading.Timer
【发布时间】:2012-08-13 16:33:23
【问题描述】:

如何在它的回调方法中停止System.Threading.Timer。我引用了 MSDN,但找不到任何有用的东西。请帮忙。

【问题讨论】:

标签: c# multithreading timer


【解决方案1】:

首先,回调方法必须在范围内包含计时器实例。

然后是简单的咒语

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

将关闭计时器。我相信,定时器可能会在更改后再次调用回调方法,具体取决于它所处的状态。

【讨论】:

  • 最好将其丢弃,因为这样可以更好地捕捉语义。它也可能更快。
  • 取决于计时器是稍后重新启动还是您已完成。 OP 指定她想“停止计时器”,而不是“破坏计时器”。计时器实例及其生命周期由其创建者负责。
  • yap 那个解决方案就是问题所在,线程不会立即停止。
【解决方案2】:
timer.Change(Timeout.Infinite, Timeout.Infinite);

【讨论】:

  • 以后想重启怎么办?
【解决方案3】:

试试这个:

如果您愿意,可以让计时器继续触发回调方法并包含以下代码

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

也请查看此链接:

Stopping timer in its callback method

【讨论】:

    【解决方案4】:

    您可以直接拨打myTimer.Change(Timeout.Infinite, Timeout.Infinite)

    从技术上讲,只需将第一个参数 (dueTime) 指定为 Timeout.Infinite 即可停止计时器。

    如需了解更多信息,请参阅Timer.Change Method

    【讨论】:

    • 最好将其丢弃,因为这样可以更好地捕捉语义。它也可能更快。
    • 这取决于用户是否永久停止计时器,或者他们是否只是暂停一段时间并可能在以后重新启动它。如果您使用.Dispose() 来简单地暂停计时器,如果您想重新启动它,或者只是更改dueTime 或期限,则会遇到问题。在这些情况下,使用timer.Change() 会更安全(也更容易)。
    【解决方案5】:

    我发现 Change(Timeout.Infinite, Timeout.Infinite) 不太可靠,并在 AutoReset = false 的情况下切换到 System.Timers.Timer。

    【讨论】:

      【解决方案6】:

      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();
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 1970-01-01
        相关资源
        最近更新 更多