c#System.Threading.Timer等待处理

时间:2012-11-15 11:18:28

标签: c# multithreading timer dispose

我有一个使用Timer的课程。该类实现IDispose。我想在Dispose方法中等待,直到计时器不会再次触发。

我这样实现:

private void TimerElapsed(object state)
{
    // do not execute the callback if one callback is still executing
    if (Interlocked.Exchange(ref _timerIsExecuting, 1) == 1) 
        return;

    try
    {
        _callback();
    }
    finally
    {
        Interlocked.Exchange(ref _timerIsExecuting, 0);
    }
}

public void Dispose()
{
    if (Interlocked.Exchange(ref _isDisposing, 1) == 1)
        return;

    _timer.Dispose();

    // wait until the callback is not executing anymore, if it was
    while (_timerIsExecuting == 0) 
    { }

    _callback = null;
}

此实施是否正确?我认为这主要取决于_ timerIsExecuting == 0是否为原子操作的问题。或者我必须使用WaitHandle。对我来说,它似乎会使代码变得不必要地复杂化......

我不是多线程专家,所以对任何建议都会感到高兴。

3 个答案:

答案 0 :(得分:8)

除非您有理由不使用System.Threading.Timer 这有一个带有等待句柄的Dispose方法

你可以做点什么,

private readonly Timer Timer;
private readonly ManualResetEvent TimerDisposed;
public Constructor()
{
    Timer = ....;
    TimerDisposed = new ManualResetEvent(false);
}

public void Dispose()
{
    Timer.Dispose(TimerDisposed);
    TimerDisposed.WaitOne();
    TimerDisposed.Dispose();
}

答案 1 :(得分:3)

一般来说,人们可以使用Timer.Dispose(WaitHandle)方法,但有一些陷阱:

陷阱

  • 支持多次处理(请参阅here
  

如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用。如果多次调用Dispose方法,则该对象不得抛出异常。除了Dispose之外的实例方法可以在已经处理资源时抛出ObjectDisposedException。

  • Timer.Dispose(WaitHandle)可以返回false。它是这样做的,以防它已被处理(我必须查看源代码)。在这种情况下,它赢了设置WaitHandle - 所以不要等待它! (注意:应支持多次处理)

  • 未处理WaitHandle超时。说真的 - 如果你对超时不感兴趣,还等什么呢?
  • 提及的并发问题here on msdn,其中{/ 1}}可以在(而不是之后)处理期间发生
  • ObjectDisposedException与 - Timer.Dispose(WaitHandle)等待处理无法正常工作,或者与人们的期望不同。例如,以下工作(它永远阻止):
Slim

解决方案

好吧标题有点"大胆"我想,但下面是我尝试处理这个问题 - 一个处理双重处理,超时和 using(var manualResetEventSlim = new ManualResetEventSlim) { timer.Dispose(manualResetEventSlim.WaitHandle); manualResetEventSlim.Wait(); } 的包装器。它虽然没有提供ObjectDisposedException上的所有方法,但可以随意添加它们。

Timer

答案 2 :(得分:-1)

  

为什么需要手动配置定时器?没有其他的   解。根据经验,您最好将此工作留给GAC。 -   LMB 56分钟前

     

我正在开发一个ASP.NET应用程序。计时器在HttpApplication的Dispose调用时处理。原因:一个回调   可以访问日志系统。所以我必须保证以前   配置计时器的记录系统。 - SACO 50分钟前

看起来你有一个Producer / Consumer模式,使用定时器作为Porducer。

在这种情况下我要做的是创建一个ConcurrentQueue()并使计时器将作业排入队列。然后,使用另一个安全线程来读取和执行作业。

这可以防止作业与另一个作​​业重叠,这似乎是代码中的一项要求,也可以解决计时器处理问题,因为您可以在添加作业之前yourQueue == null

这是最好的设计。

另一个简单但不健全的解决方案是在try块中运行回调。我不建议手动配置定时器。