我有一个使用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
。对我来说,它似乎会使代码变得不必要地复杂化......
我不是多线程专家,所以对任何建议都会感到高兴。
答案 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)
方法,但有一些陷阱:
如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用。如果多次调用Dispose方法,则该对象不得抛出异常。除了Dispose之外的实例方法可以在已经处理资源时抛出ObjectDisposedException。
Timer.Dispose(WaitHandle)
可以返回false。它是这样做的,以防它已被处理(我必须查看源代码)。在这种情况下,它赢了设置WaitHandle
- 所以不要等待它! (注意:应支持多次处理)WaitHandle
超时。说真的 - 如果你对超时不感兴趣,还等什么呢?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
块中运行回调。我不建议手动配置定时器。