我能够在Threading.Timer的回调函数中销毁它吗?

12

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

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

在回调函数内如何释放该计时器,或通过其他方法解决?更新:让我解释一下情况。我想尝试调用“保存”方法,同时它会抛出异常。如果成功,我需要停止计时器。


你尝试过将其赋值给一个变量,然后访问该变量吗? - user541686
为什么你不能简单地将Timer包装在一个using语句中? - Cody Gray
1
@Cody 因为计时器可能会比预期更早地被处理掉。 - OJ.
5个回答

17

试一下这个:

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并不在乎它是否被多次处理。


我的损失,是你的收获。我经常试图把事情搞得太复杂了。对于正确而简单的解决方案加1。 - Cody Gray
3
我认为这不是100%线程安全的,以下(极不可能发生的)一系列事件在理论上可能会发生:1. 创建计时器。2. <切换上下文> 3. 在线程池上触发回调。4. <切换上下文> 5. 赋值发生。线程安全的方法可能是创建具有无限超时的计时器,以强制在线程池回调之前进行赋值,然后使用Change()设置重复属性。 - Chuu
@Chuu:好观点。我认为你是正确的。我已经相应地更改了我的答案。 - Jakob Christensen
@JakobChristensen Resharper 给出了“访问修改的闭包”警告?在这种情况下忽略该警告是否安全? - redandblue
@user2383728,Resharper 可能会抱怨我们在创建了一个围绕 timer 的闭包之后,在委托外部修改了它。在这种情况下,您可以忽略此警告。 - Jakob Christensen
显示剩余2条评论

4
这里有一个更好的方法来实现这个功能。当你使用只有一个参数(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


3

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

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



}

注意:这是未经测试的代码。请检查它是否可用并进行更新。

0
你需要在某个地方存储计时器的引用,并将其作为状态传递给计时器对象本身。尝试创建一个类似于以下内容的类:
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);

0

如果你使用多线程或多任务,请小心!如果是这样,在这里你可以找到代码和一个取消方法扩展的解决方案(.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);
    }
}

敬礼, Juanlu,ElGuerre


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接