如何在C# Windows Service中创建等待主方法结束的定时器
解决C# Windows Service定时器重叠执行问题
针对你遇到的定时器在前一次ImportXML方法执行完成前就触发的问题,这里提供几种实用的解决方案:
方案一:执行前停止定时器,完成后重启
这是最直接的处理方式,在方法开始时停止定时器,确保当前执行过程中不会触发新的调用,执行完成(包括异常情况)后再重启定时器:
private void ImportXML(object sender, ElapsedEventArgs e) { var timer = sender as System.Timers.Timer; timer.Stop(); try { // 这里放置你的XML导入业务逻辑 // ... } finally { // 无论执行成功还是失败,都重启定时器 timer.Start(); } }
这种方式能保证每次任务执行完成后,才会开始下一个周期的计时。
方案二:使用锁跳过重叠触发
如果希望当前任务在执行时,忽略后续的定时器触发(而不是等待),可以用排他锁来控制:
private static readonly object _executeLock = new object(); private void ImportXML(object sender, ElapsedEventArgs e) { // 尝试获取锁,获取失败说明已有任务在执行,直接返回 if (!Monitor.TryEnter(_executeLock)) { return; } try { // 你的XML导入业务逻辑 // ... } finally { Monitor.Exit(_executeLock); } }
这种方式下,若前一次任务还未完成,新的定时器触发会直接跳过,不会堆积任务。
方案三:改用System.Threading.Timer控制执行间隔
如果需要严格保证两次任务执行结束之间的间隔为1小时,可以使用System.Threading.Timer,它支持在任务完成后再安排下一次执行:
private System.Threading.Timer _taskTimer; private const int OneHourMs = 3600000; // 1小时对应的毫秒数 // 在服务启动方法中初始化定时器 public void OnStart(string[] args) { // 首次立即执行,后续执行完成后间隔1小时再触发 _taskTimer = new System.Threading.Timer(ExecuteImport, null, 0, Timeout.Infinite); } private void ExecuteImport(object state) { try { // 调用你的XML导入方法 ImportXML(); } finally { // 安排下一次执行,间隔1小时 _taskTimer.Change(OneHourMs, Timeout.Infinite); } } // 原有的XML导入方法 private void ImportXML() { // ... 业务逻辑 ... }
这种方式的计时是从任务结束时开始算,避免了固定时间点触发导致的重叠问题。
内容的提问来源于stack exchange,提问作者Thiago Moura
相关产品推荐
相关产品推荐

