【问题标题】:Can I dispose a Threading.Timer in its callback?我可以在其回调中处理 Threading.Timer 吗?
【发布时间】:2015-12-22 20:04:17
【问题描述】:

我正在使用Threading.Timer,例如:

new Timer(new TimerCallback(y=>
{
    try
    {
        Save(Read(DateTime.Now));
        // here i want to dispose this timer
    }
    catch
    {                          
    }
}),null,100000,10000);

如何在回调中处理此计时器。或解决方法? 更新:让我解释一下情况。我想尝试调用方法“Save”,而它会引发异常。如果它有效,我需要停止计时器。

【问题讨论】:

  • 您是否尝试过将其分配给变量然后访问该变量?
  • 为什么不能简单地将Timer 包装在using 语句中?
  • @Cody 因为计时器可能会比预期的更早被释放。

标签: .net callback timer dispose


【解决方案1】:

试试这个:

Timer timer = null;
timer = new Timer(new TimerCallback(y =>
{    
    try    
    {
        Save(Read(DateTime.Now));        
        // here i want to dispose this timer
        timer.Dispose();    
    }    
    catch    
    {    
    }
}));
timer.Change(10000, 10000);

编辑:

我根据 Chuu 的建议稍微修改了上面的代码。请注意,如果 TimerCallback 被不同的计时器事件同时调用,Timer.Dispose 最终可能会被多次调用。幸运的是,Timer 并不关心它是否被多次处理。

【讨论】:

  • 哇,我在这里试图让这个问题变得复杂。显而易见的解决方案确实是 Dispose 声明。我认为无论出于何种原因,这已经被排除为“不是一个选项”。
  • 我想这太明显了:-)
  • 我的损失,你的收获。我经常试图把事情弄得太复杂。为正确但简单的解决方案 +1。
  • 我认为这不是 100% 线程安全的,理论上可能会发生以下(非常不可能)系列事件: 1. 创建了计时器。 2. 3. 线程池上的回调触发 4. 5. 分配发生。线程安全的方法可能是创建具有无限超时的计时器以在线程池回调之前强制分配,然后使用 Change() 设置循环属性。
  • @Chuu:好点。我想你是对的。我相应地改变了我的答案。
【解决方案2】:

您需要将计时器的引用保存在一个变量中 -

public class MyClass
{
    private Timer _timer;

    public void StartTimer()
    {
        _timer =  new Timer(new TimerCallback(y=>{
                            try
                            {
                                Save(Read(DateTime.Now));
                                _timer.Dispose();
                            }
                            catch { 

                            }
                        }),null,100000,10000);
    }



}

注意:这是未经测试的代码。请检查它是否有效并更新。

【讨论】:

    【解决方案3】:

    这里有一个更好的方法来做到这一点。当您使用只有一个参数(TimerCallback)的构造函数时,传递给回调的状态将是计时器本身。

    Timer timer = new Timer(o =>
    {
         ((Timer)o).Dispose();
         //Your code here     
    });
    
    //Start the timer
    timer.Change(100000,10000);
    

    这是来自 msdn 文档的示例:

    public void StartTimer(int dueTime)
    {
        Timer t = new Timer(new TimerCallback(TimerProc));
        t.Change(dueTime, 0);
    }
    
    private void TimerProc(object state)
    {
        // The state object is the Timer object.
        Timer t = (Timer) state;
        t.Dispose();
        Console.WriteLine("The timer callback executes.");
    }
    

    http://msdn.microsoft.com/en-us/library/ms149618(v=vs.110).aspx

    【讨论】:

      【解决方案4】:

      您必须在某处存储对计时器的引用,并将其作为状态传递给计时器对象本身。尝试创建一个类似这样的类:

      public class TimerContainer
      {
        public Timer Timer { get; set; }
      }
      

      然后像这样在你的方法中使用它:

      Action<object> tcb = state =>
      {
        var container = (TimerConatiner)state;
        try
        {
          Save(Read(DateTime.Now));
          container.Timer.Dispose();
        }
        catch
        {
          // whatever...
        }
      };
      
      var container = new TimerContainer();
      container.Timer = new Timer(tcb, container, 100000, 10000);
      

      【讨论】:

        【解决方案5】:

        使用多线程或多任务时要小心!如果是这样,这里是 CancelAfter 方法扩展器 (.net 4.0) 的代码和解决方案:

               private static object syncObj = new object();
        
               public static void CancelAfter(this CancellationTokenSource source, int timeoutMilliseconds, Action code = null)
            {
                if (timeoutMilliseconds == 0) return; // No timeout
        
                if (source == null)
                {
                    throw new NullReferenceException();
                }
                if (timeoutMilliseconds < -1)
                {
                    throw new ArgumentOutOfRangeException("timeout");
                }
                Timer timer = new Timer(delegate(object self)
                {
                    lock (syncObj)
                    {
                        try
                        {
                            if (null != code)
                                code.Invoke();
                            source.Cancel();
        
                            ((IDisposable)self).Dispose();
                        }
                        catch (ObjectDisposedException)
                        {
                        }                   
                    }
                });
                timer.Change(timeoutMilliseconds, -1);
            }
        }
        

        问候, 胡安,埃尔盖尔

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-27
          • 2015-08-27
          • 2010-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多