C#中实现每60秒执行函数且避免重复执行长耗时任务
C# Timer 实现跳过正在执行的任务周期
核心思路很直接:用一个线程安全的标记跟踪任务运行状态,每次Timer触发时先检查标记——任务没在执行就启动,正在执行就直接跳过当前周期,等下一个60秒再重新检查。
具体实现步骤
1. 定义线程安全的执行标记
Timer的Tick事件由线程池线程触发,和任务执行线程可能不是同一个,必须用原子操作保证标记的可靠性,这里用Interlocked类来操作标记:
// 0 = 任务未执行,1 = 任务正在执行 private int _isTaskRunning = 0; private Timer _timer;
2. 初始化Timer并修改Tick事件逻辑
在Tick事件中,先尝试将标记设为“正在执行”,如果设置成功(说明之前无任务运行),就执行长耗时任务;如果失败,直接跳过本次触发:
public void SetupTimer() { _timer = new Timer(); _timer.Tick += OnTimerTick; _timer.Interval = 60 * 1000; // 60秒触发间隔 _timer.Start(); } private void OnTimerTick(object sender, EventArgs e) { // 原子操作:尝试把_isTaskRunning从0改为1,返回修改前的值 if (Interlocked.Exchange(ref _isTaskRunning, 1) == 0) { try { // 执行你的长耗时任务 RunLongRunningProcess(); } finally { // 无论任务成功/失败,都重置标记,确保后续任务能正常触发 Interlocked.Exchange(ref _isTaskRunning, 0); } } // 如果Exchange返回非0,说明任务仍在运行,直接跳过本次触发 } private void RunLongRunningProcess() { // 这里写你的长运行进程逻辑,比如耗时数分钟的操作 // 示例:模拟5秒耗时任务 Thread.Sleep(5000); }
关键细节说明
Interlocked.Exchange是原子操作,彻底避免多线程下的竞态问题,保证标记状态绝对准确。try/finally块是核心:哪怕任务抛出异常,标记也会被重置,不会出现“任务永远被标记为正在执行”的死锁情况。- 这种逻辑完全匹配你的需求:每次Timer到点就检查任务状态,正在执行就跳过,否则执行,循环往复。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

