Sync past timer. End Timer

Regarding this quote from MSDN about System.Timers.Timer:

The Timer.Elapsed event is raised by ThreadPool, so that the event processing method can work on one thread at the same time that the call to the Timer.Stop method works on another thread. This can lead to an expired event that occurs after the Stop method is called. This race condition cannot be prevented simply by comparing the SignalTime property with the time when the Stop method because the event processing method can already be executed when the Stop method is called or it can start execution between the moment when the Stop method is called and the moment when the stop time is saved. If it is important to prevent the thread that calls the Stop method from being processed while the method is still executing, use a reliable synchronization mechanism like the Monitor class or CompareExchange method. Code that uses the CompareExchange method can be found in the example for the Timer.Stop method.

Could someone give an example of a “reliable synchronization mechanism” such as the Monitor class to explain what this means?

I think this means using locks somehow, but I'm not sure how you implement this.

+6
synchronization c # timer
source share
5 answers

Stopping a reliable System.Timers.Timer is really a big effort. The most serious problem is that the thread threads that it uses to trigger the Elapsed event can back up due to the thread scheduler algorithm. Having multiple backup calls is not unusual, and hundreds of them are technically possible.

You will need two synchronizations, one of which ensures that you stop the timer only when the Elapsed handler is not running, the other to ensure that these backup TP threads do no harm. Like this:

System.Timers.Timer timer = new System.Timers.Timer(); object locker = new object(); ManualResetEvent timerDead = new ManualResetEvent(false); private void Timer_Elapsed(object sender, ElapsedEventArgs e) { lock (locker) { if (timerDead.WaitOne(0)) return; // etc... } } private void StopTimer() { lock (locker) { timerDead.Set(); timer.Stop(); } } 

Consider the AutoReset property set to false. This fragile other way, the Elapsed event is called from an internal .NET method that catches the Exception. Very unpleasant, your timer code stops working without any diagnostics at all. I don't know the story, but there must have been another team in MSFT that annoyed and puffed out this mess and wrote System.Threading.Timer. Highly recommended.

+11
source share

Here is what he offers.

Monitor is the class that the C # compiler uses for the lock statement.

The above is only a problem if it is a problem in your situation. The whole operator basically translates as "You can get a timer event that will happen immediately after calling Stop (). If this is a problem, you will need to deal with it." Depending on what your timer does, this may be a problem, or it may not.

If this is a problem, the Timer.Stop page shows a reliable way (using Interlocked.CompareExchange ) to handle this. Just copy the code from the sample and change if necessary.

0
source share

Try:

 lock(timer) { timer.Stop(); } 
0
source share

Here is a very simple way to prevent this race condition from appearing:

 private object _lock = new object(); private Timer _timer; // init somewhere else public void StopTheTimer() { lock (_lock) { _timer.Stop(); } } void elapsed(...) { lock (_lock) { if (_timer.Enabled) // prevent event after Stop() is called { // do whatever you do in the timer event } } } 
0
source share

It seems that the timer is not thread safe. You must synchronize all calls with the lock. lock (object) {} is actually just a short hand for a simple call to the monitor.

0
source share

All Articles