Synchronizing a Timers.Timer elapsed method when stopping

后端 未结 5 1520
情书的邮戳
情书的邮戳 2020-12-19 09:18

With reference to this quote from MSDN about the System.Timers.Timer:

The Timer.Elapsed event is raised on a ThreadPool thread, so the event-handl

5条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-19 09:28

    Stopping a System.Timers.Timer reliably is indeed a major effort. The most serious problem is that the threadpool threads that it uses to call the Elapsed event can back up due to the threadpool scheduler algorithm. Having a couple of backed-up calls isn't unusual, having hundreds is technically possible.

    You'll need two synchronizations, one to ensure you stop the timer only when no Elapsed event handler is running, another to ensure that these backed-up TP threads don't do any 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 setting the AutoReset property to false. That's brittle another way, the Elapsed event gets called from an internal .NET method that catches Exception. Very nasty, your timer code stops running without any diagnostic at all. I don't know the history, but there must have been another team at MSFT that huffed and puffed at this mess and wrote System.Threading.Timer. Highly recommended.

提交回复
热议问题