System.Timers.Timer and Close/Dispose

  • Thread starter Thread starter AMercer
  • Start date Start date
A

AMercer

The short form of this post is as follows. For an instance of
System.Timers.Timer, after setting Enabled to False, is there a foolproof way
to tell if an Elapsed event will or will not fire?

The long form follows. I have a class, MyClass, that declares

Private WithEvents MyTimer As System.Timers.Timer

Sub New for MyClass initializes MyTimer to fire Elapsed events every second.
I have an Elapsed event handler and some public methods. With SyncLock,
I've made MyClass instances thread safe. Everything works fine.

System.Timers.Timer has Close and Dispose methods, so I when I want to
destroy an instance of MyClass, I should Close or Dispose MyTimer. I've
coded MyClass.Close to look like this:

MyTimer.Enabled = False
' some cleanup I need to do
Sleep(100) ' let fire an enroute MyTimer.Elapsed
MyTimer.Dispose() ' per IDisposable
' some more cleanup I need to do

The reason for the Sleep is because of how Windows/.NET executes
MyTimer.Elapsed events. The Timer.Stop documentation says:

"The Elapsed event is raised on a ThreadPool thread, so the event-handling
method might run on one thread at the same time that a call to the Stop
method runs on another thread. This might result in the Elapsed event being
raised after the Stop method is called."

Stop and Enabled=False do the same thing. The Timer.Stop documentation goes
on to give a somewhat elaborate mechanism to overcome contention and race
conditions that might arise. My solution is Sleep(100).

I don't like my use of Sleep. I don't like the elaborate mechanism in the
documentation because it looks like it could fail if someone is messing with
thread priorities (note that the mechanism uses Sleep(0)).

So, the question is: For an instance of System.Timers.Timer, after setting
Enabled to False, is there a foolproof way to tell if an Elapsed event will
or will not fire?
 
[...]
I don't like my use of Sleep. I don't like the elaborate mechanism in
the
documentation because it looks like it could fail if someone is messing
with
thread priorities (note that the mechanism uses Sleep(0)).

The mechanism shown in that sample looks reliable to me, as far as it
goes. They aren't using Sleep() as part of the synchronization...they're
just putting it there to ensure that the "control" thread doesn't chew up
the CPU while trying to take control of the status variable (and they use
Sleep(1), not Sleep(0)...there's a significant difference between the two).

Personally, I don't like that example very much, mainly because it is so
complicated. It's complicated because they wanted to demonstrate
something a little more elaborate than just stopping the timer. They
could have dealt with a race condition just by setting a volatile boolean
variable that signals to the timer event handler that the timer's been
stopped and so shouldn't do any work. But in the example they also want
to _know_ whether the timer was simply stopped or if it had to rely on
that flag to stop processing, so that the behavior could be reported back
later.

In doing so, they want a variable that they look at and then set according
to the current value, and the easiest reliable way to do that is with
Interlocked.CompareExchange(). If it wasn't for that need, they could've
just set a flag.
So, the question is: For an instance of System.Timers.Timer, after
setting
Enabled to False, is there a foolproof way to tell if an Elapsed event
will
or will not fire?

That depends on your definition of "after". I believe that the Timer
class is reliable in the sense that if you disable the timer, then _after_
that point the timer event won't be raised. The problem comes in that the
timer event may already have started to be raised by the time you disable
the timer, and yet it might not have completely executed by that point.

So you can still get code handling the timer executing after you've
disabled the timer.

The fact is, even the code sample you've seen on MSDN doesn't really
address that issue per se. After all, the handler could still already be
executing past the point at which is actually attempts to check the status
variable they're using. Even in that example, it's still possible to have
timer handler code execute after disabling the timer.

What that code sample does address is the ability for information to flow
in both directions, so that the control thread can be sure that by the
time it gets past that while loop, the timer event handler is done
working. It's only necessary to do this (or something like it) if you
have code in the thread modifying the timer that needs to be mutually
exclusive with code in the timer event handler itself. And the sample
clearly states this in the comments, by the way.

So this brings us back to your question: if by "fire" you mean that you
may have event handler code executing after you stop the timer,
no...there's no way to tell if that will happen. You can be assured that
the event itself won't be raised after you disable the timer, but if it's
already been raised before you do that, the best you can do is determine
whether the event handler code is executing and act accordingly.

Now, you mentioned that you want to call Dispose(). You don't say so
explicitly, but there seems to be an implication in your post that this is
the reason you want to synchronize access to the timer's event handler.
If so, then I don't think this is a concern. I prefer the Threading.Timer
or Forms.Timer timers and so don't have a lot of first-hand experience
with the Timers.Timer, but my understanding is that there's no problem if
you call Dispose() or Close() on the timer while the event handler is
executing. I believe that the timer just queues the method that raises
the event on the ThreadPool thread, and that's not something that once
started should be affected by a call to dispose the timer object itself.

Pete
 
Thanks for your thoughtful reply. My concern all along was about disposing
the timer while there was an Elapsed event pending. By pending I mean that
the event has been raised but my handler hasn't yet been called. I was
worried about something going wrong with the timer after it had been
disposed. The 'something' would likely be an extremely rare unhandled
exception of some undetermined type, and I wanted to take steps to prevent
that.

Also, I'll take a look at Threading.Timer. My investment in Timers.Timer
isn't much. I can't use Forms.Timer for my problem.

Peter Duniho said:
[...]
I don't like my use of Sleep. I don't like the elaborate mechanism in
the
documentation because it looks like it could fail if someone is messing
with
thread priorities (note that the mechanism uses Sleep(0)).

The mechanism shown in that sample looks reliable to me, as far as it
goes. They aren't using Sleep() as part of the synchronization...they're
just putting it there to ensure that the "control" thread doesn't chew up
the CPU while trying to take control of the status variable (and they use
Sleep(1), not Sleep(0)...there's a significant difference between the two).

Personally, I don't like that example very much, mainly because it is so
complicated. It's complicated because they wanted to demonstrate
something a little more elaborate than just stopping the timer. They
could have dealt with a race condition just by setting a volatile boolean
variable that signals to the timer event handler that the timer's been
stopped and so shouldn't do any work. But in the example they also want
to _know_ whether the timer was simply stopped or if it had to rely on
that flag to stop processing, so that the behavior could be reported back
later.

In doing so, they want a variable that they look at and then set according
to the current value, and the easiest reliable way to do that is with
Interlocked.CompareExchange(). If it wasn't for that need, they could've
just set a flag.
So, the question is: For an instance of System.Timers.Timer, after
setting
Enabled to False, is there a foolproof way to tell if an Elapsed event
will
or will not fire?

That depends on your definition of "after". I believe that the Timer
class is reliable in the sense that if you disable the timer, then _after_
that point the timer event won't be raised. The problem comes in that the
timer event may already have started to be raised by the time you disable
the timer, and yet it might not have completely executed by that point.

So you can still get code handling the timer executing after you've
disabled the timer.

The fact is, even the code sample you've seen on MSDN doesn't really
address that issue per se. After all, the handler could still already be
executing past the point at which is actually attempts to check the status
variable they're using. Even in that example, it's still possible to have
timer handler code execute after disabling the timer.

What that code sample does address is the ability for information to flow
in both directions, so that the control thread can be sure that by the
time it gets past that while loop, the timer event handler is done
working. It's only necessary to do this (or something like it) if you
have code in the thread modifying the timer that needs to be mutually
exclusive with code in the timer event handler itself. And the sample
clearly states this in the comments, by the way.

So this brings us back to your question: if by "fire" you mean that you
may have event handler code executing after you stop the timer,
no...there's no way to tell if that will happen. You can be assured that
the event itself won't be raised after you disable the timer, but if it's
already been raised before you do that, the best you can do is determine
whether the event handler code is executing and act accordingly.

Now, you mentioned that you want to call Dispose(). You don't say so
explicitly, but there seems to be an implication in your post that this is
the reason you want to synchronize access to the timer's event handler.
If so, then I don't think this is a concern. I prefer the Threading.Timer
or Forms.Timer timers and so don't have a lot of first-hand experience
with the Timers.Timer, but my understanding is that there's no problem if
you call Dispose() or Close() on the timer while the event handler is
executing. I believe that the timer just queues the method that raises
the event on the ThreadPool thread, and that's not something that once
started should be affected by a call to dispose the timer object itself.

Pete
 
Back
Top