System.Timers.Timer执行方法的时候,会开一个线程去执行,如果使用锁(方法3)避免重入,可能会有多个线程等在那里执行。
按照单片机的写法要推荐方法1
但是C#提供了方便的定时器Stop方法,所以可用方法2,但是这种方法有个弊端,就是如果要停止定时器的时候,如果有线程在执行,又会把定时器打开,所以还是推荐方法1吧。
- 使用标志位:设置一个标志位来跟踪定时器是否已经在执行。在定时器的回调函数中,首先检查这个标志位。如果标志位表示定时器已经在执行,则立即退出,避免重入。
private bool isTimerRunning = false; private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ if (isTimerRunning) return; isTimerRunning = true; try { // 定时器的逻辑代码 } finally { isTimerRunning = false; }
}
- 停止定时器:在定时器的回调函数开始时停止定时器,并在函数结束时重新启动它。这样可以确保在函数执行期间不会触发另一个回调。
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ timer.Stop(); try { // 定时器的逻辑代码 } finally { timer.Start(); }
}
- 使用锁:使用lock语句或Mutex来同步访问定时器回调函数中的代码。这可以确保即使多个线程同时进入回调函数,也只有一个线程可以执行其中的代码。
private object timerLock = new object(); private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ lock (timerLock) { // 定时器的逻辑代码 }
}
- AutoReset属性:System.Timers.Timer类有一个AutoReset属性,当设置为false时,定时器在触发一次Elapsed事件后不会自动重置,需要手动重启定时器。这可以防止定时器在上一个回调还未完成时再次触发
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += OnTimedEvent;
timer.Start();private void OnTimedEvent(Object source, ElapsedEventArgs e)
{try { // 定时器的逻辑代码 } finally { timer.Start(); }
}