10

When you dispose a “raw” .net timer, you can pass in a wait handle to be called once the Win32 timer has been destroyed and you can them assume that your call back will not be called. (And the timer will be considered "dead" by the GC)

How do I do this with a System.Timers.Timer?

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317

2 Answers2

3

Set a flag before you call dispose, and check this flag in your elapsed handler. Even if the timer does fire, the flag will prevent any associated handler code from being run. You could formalize this pattern by writing a wrapper for the timer.

Make sure your flag is marked as volatile as it will be accessed from different threads.

Tim Lloyd
  • 37,954
  • 10
  • 100
  • 130
  • @Hans if the volatile flag is set before calling dispose, then a timer thread will see it if a subsequent elapsed event occurs. What is the problem you see here? – Tim Lloyd Nov 25 '10 at 18:21
  • What is the scope for the flag? Especially in the case of a wrapper with say, a Stop method that sets the flag and disposes the timer. Isn't the most likely thing that will happen after calling Stop going to be that the wrapper itself will go out of scope and get GC'ed, invalidating the flag? – Mike Oct 28 '15 at 01:38
0

As System.Timers.Timer and System.Windows.Forms.Timer both use the ThreadPool it doesn't have a handle to an operating system timer, so there is no native timer resource that's disposed of - just a completed thread. I'm not sure you can capture a thread being recycled by the ThreadPool but I might be wrong.

You could maybe roll your own (I haven't tested this, and taking a ManualResetEvent in Dispose might be more useful):

void Run()
{
    ManualResetEvent resetEvent = new ManualResetEvent(false);

    System.Threading.Timer timer = new System.Threading.Timer(delegate { Console.WriteLine("Tick"); });
    timer.Dispose(resetEvent);

    MyTimer t = new MyTimer();
    t.Interval = 1000;
    t.Elapsed += delegate { t.Dispose(resetEvent); };

    resetEvent.WaitOne();
}


public class MyTimer : System.Timers.Timer
{
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
    }

    public virtual void Dispose(WaitHandle handle)
    {
        handle.SafeWaitHandle.Close();
        Dispose();
    }
}
Chris S
  • 64,770
  • 52
  • 221
  • 239
  • I think the System.Timers.Timer Disposed event fires as soon as it has called the System.Threading.Timer Dispose method. – Ian Ringrose Nov 26 '10 at 09:07
  • @Ian The event is being called inside `Component.Dispose(disposing)` so providing you signal the WaitHandle before calling base.Dispose(), and use the custom Dispose(WaitHandle) it should fire after. – Chris S Nov 26 '10 at 09:52