C# System.Timers.Timer长期运行后出现重叠日志问题求助
C# WinForm定时器长期运行后出现重复日志问题
我开发了一个C# WinForm程序,使用System.Timers.Timer每秒执行一次变量检查、日志记录,满足条件时触发后续函数。程序连续运行超过两周后,出现定时器日志重叠问题:定时器周期为1秒,但日志中同一秒内多次输出相同内容(如示例中14:06:05多次输出B)。
已排查情况
- 在问题出现的相同环境测试程序,未复现症状;
- 同时运行多个程序实例,未复现症状;
- 异步添加多个同类型定时器,日志功能失效;
- 未找到同类症状的公开案例。
相关代码
定时器初始化代码
该初始化方法仅在程序启动(Form_load())时调用一次。
private static System.Timers.Timer TestEndDetection_Timer_; private void SetUp_TestEndDetection_Timer_() { TestEndDetection_Timer_ = new System.Timers.Timer(1000); TestEndDetection_Timer_.Elapsed += TestEndDetection_Timer_Event; TestEndDetection_Timer_.AutoReset = true; TestEndDetection_Timer_.Enabled = true; }
定时器事件处理代码
private void TestEndDetection_Timer_Event(Object source, ElapsedEventArgs e) { defrostCount++; CheckForIllegalCrossThreadCalls = false; if (NowTesting && AutoDefrost && checkBox2.Checked) { TestEndDetectionDealyTimer++; if (TestEndDetectionDealyTimer > 180) { bool Fix1End = false; bool Fix2End = false; bool Fix3End = false; bool Fix4End = false; bool Fix5End = false; bool Fix6End = false; bool Fix1Done = false; bool Fix2Done = false; bool Fix3Done = false; bool Fix4Done = false; bool Fix5Done = false; bool Fix6Done = false; bool Fix1Power = false; bool Fix2Power = false; bool Fix3Power = false; bool Fix4Power = false; bool Fix5Power = false; bool Fix6Power = false; Fix1Done = File.Exists(@"Z:\result\fix1\hdiag.log"); Fix2Done = File.Exists(@"Z:\result\fix2\hdiag.log"); Fix3Done = File.Exists(@"Z:\result\fix3\hdiag.log"); Fix4Done = File.Exists(@"Z:\result\fix4\hdiag.log"); Fix5Done = File.Exists(@"Z:\result\fix5\hdiag.log"); Fix6Done = File.Exists(@"Z:\result\fix6\hdiag.log"); defrostlogger("TESTDONE: "+Convert.ToInt32(Fix1Done) + "/" + Convert.ToInt32(Fix2Done) + "/" + Convert.ToInt32(Fix3Done) + "/" + Convert.ToInt32(Fix4Done) + "/" + Convert.ToInt32(Fix5Done) + "/" + Convert.ToInt32(Fix6Done)); Fix1Power = m_ucFixInfo[1].PowerStat; Fix2Power = m_ucFixInfo[2].PowerStat; Fix3Power = m_ucFixInfo[3].PowerStat; Fix4Power = m_ucFixInfo[4].PowerStat; Fix5Power = m_ucFixInfo[5].PowerStat; Fix6Power = m_ucFixInfo[6].PowerStat; defrostlogger("POWER: "+Convert.ToInt32(Fix1Power) + "/" + Convert.ToInt32(Fix2Power) + "/" + Convert.ToInt32(Fix3Power) + "/" + Convert.ToInt32(Fix4Power) + "/" + Convert.ToInt32(Fix5Power) + "/" + Convert.ToInt32(Fix6Power)); if (Fix1Done || !Fix1Power) { Fix1End = true; } else { Fix1End = false; } if (Fix2Done || !Fix2Power) { Fix2End = true; } else { Fix2End = false; } if (Fix3Done || !Fix3Power) { Fix3End = true; } else { Fix3End = false; } if (Fix4Done || !Fix4Power) { Fix4End = true; } else { Fix4End = false; } if (Fix5Done || !Fix5Power) { Fix5End = true; } else { Fix5End = false; } if (Fix6Done || !Fix6Power) { Fix6End = true; } else { Fix6End = false; } if (Fix1End && Fix2End && Fix3End && Fix4End && Fix5End && Fix6End && AutoDefrostRunStat && TestEndCount < 20) { TestEndCount++; } if (TestEndCount > 10) { if (button13.Text == "Door Open" && DefrostAvailable) { defrostlogger("A"); RunDefrost(); AutoDefrostRunStat = false; NowTesting = false; TestEndCount = 0; } else { defrostlogger("B"); } } } } else { if (defrostCount % 10 == 9 && NowTesting) { Load_SV_txt(); defrostCount = 0; } } }
日志记录方法
private void defrostlogger(string msg) { using (System.IO.StreamWriter file_ = new System.IO.StreamWriter(Application.StartupPath + @"\Logs\DefrostLog_" + System.DateTime.Now.ToString("MM_dd") + ".txt", true)) { file_.WriteLine("[" + System.DateTime.Now.ToString("HH:mm:ss") + "]" + msg); } }
排查与解决建议
- 解决定时器重入问题:
System.Timers.Timer在AutoReset=true时,若前一次事件处理耗时超过1秒,会触发新的线程执行事件逻辑,导致同一周期内多次执行。可以通过加锁或修改定时器模式避免:
方案一:添加锁避免重入
方案二:关闭自动重置,手动触发下一次private static readonly object TimerLock = new object(); private void TestEndDetection_Timer_Event(Object source, ElapsedEventArgs e) { if (!Monitor.TryEnter(TimerLock)) return; try { // 原有逻辑代码 } finally { Monitor.Exit(TimerLock); } }private void SetUp_TestEndDetection_Timer_() { TestEndDetection_Timer_ = new System.Timers.Timer(1000); TestEndDetection_Timer_.Elapsed += TestEndDetection_Timer_Event; TestEndDetection_Timer_.AutoReset = false; TestEndDetection_Timer_.Enabled = true; } private void TestEndDetection_Timer_Event(Object source, ElapsedEventArgs e) { try { // 原有逻辑代码 } finally { TestEndDetection_Timer_.Start(); } } - 优化日志时间精度:将日志时间格式改为
HH:mm:ss.fff,添加毫秒级精度,便于区分事件实际触发时间,排查是否真的是同一秒内多次执行。 - 修复线程安全问题:全局变量
defrostCount、TestEndDetectionDealyTimer等未做线程同步,长期运行可能出现值异常,建议用Interlocked类操作或加锁保护。 - 优化耗时操作:事件中访问网络路径Z盘的
File.Exists可能因网络延迟导致处理超时,可将该逻辑异步化,避免阻塞定时器线程。 - 监控系统资源:长期运行后系统负载、内存泄漏可能影响定时器调度,添加内存、线程池状态监控,排查资源异常。
内容的提问来源于stack exchange,提问作者Bam_E
相关产品推荐
相关产品推荐

