Re: System.Timers.Timer and Close/Dispose by AMercer
AMercer
Wed Mar 12 14:07:02 CDT 2008
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" wrote:
> On Wed, 12 Mar 2008 08:18:00 -0700, AMercer
> <AMercer@discussions.microsoft.com> wrote:
>
> > [...]
> > 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
>