我读过很多与Windows服务和定时器相关的post,但我还没有find任何理由说明为什么我的事件处理程序仍然被触发。 任何人都可以指向正确的方向吗? 我想知道为什么发生这种情况,所以我明白如何避免这种情况。
编辑:从不调用onError事件处理程序(或者我会看到事件日志中的事件)。
计时器: System.Timers.Timer
ServiceBase: System.ServiceProcess.ServiceBase
这是抽象类:
public abstract class ABCService : ServiceBase { // Members protected Timer invocationTimer; protected Timer wellnessTimer; protected FileSystemWatcher fsw; // Constructors protected ABCService() { invocationTimer = new Timer(); wellnessTimer = new Timer(); fsw = null; invocationTimer.AutoReset = false; invocationTimer.Interval = 30000; // 30 seconds invocationTimer.Elapsed += new ElapsedEventHandler(invocationTimer_Elapsed); wellnessTimer.AutoReset = false; wellnessTimer.Elapsed += new ElapsedEventHandler(wellnessTimer_Elapsed); } // Methods protected void invocationTimer_Elapsed(object o, ElapsedEventArgs args) { try { // log to event log invocationTimer.Stop(); if ((new FileInfo(fsw.Path + "\\" + fsw.Filter)).Exists) { onCreated(this, new FileSystemEventArgs(WatcherChangeTypes.Created, fsw.Path, fsw.Filter)); } } catch (Exception x) { onError(this, new ErrorEventArgs(x)); } } protected void wellnessTimer_Elapsed(object o, ElapsedEventArgs args) { try { // log to event log wellnessTimer.Stop(); wellnessTimer.Interval = 60000; // ms if (fsw != null) { fsw.Dispose(); } fsw = new FileSystemWatcher(ConfigurationManager.AppSettings["pathKey"], ConfigurationManager.AppSettings["filterKey"]); invocationTimer.Start(); } catch (Exception x) { onError(this, new ErrorEventArgs(x)); } } protected abstract void onCreated(object o, FileSystemEventArgs args); protected virtual void onError(object o, ErrorEventArgs args) { // log to event log wellnessTimer.Start(); } protected override void OnStart(string[] args) { // log to event log wellnessTimer.Interval = 5000; // 5 seconds wellnessTimer.Start(); } protected override void OnStop() { // log to event log wellnessTimer.Stop(); } }
这是一个实例类:
public partial class Service1 : ABCService { // Members private static object locket = new object(); private static DateTime LAST_RUN_TIME = DateTime.Now.AddSeconds(-10); // Constructors public Service1() { InitializeComponent(); } // Methods protected override void onCreated(object o, FileSystemEventArgs args) { lock (locket) { // log to event log if ((DateTime.Now - LAST_RUN_TIME).Seconds >= 10) { // do stuff } else { // log to event log invocationTimer.Stop(); invocationTimer.Start(); } } } }
这是部分类的自动生成的代码:
partial class Service1 { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { // // Service1 // this.ServiceName = "Service1"; } #endregion }
那么究竟发生了什么? 我正在查看我的事件日志,并且我看到每分钟都会调用一次wellnessTimer事件处理程序。
这是我所想的,但我显然是错的:
1. Service is started via MMC 2. OnStart() method is invoked 3. wellnessTimer interval is set to 5 seconds 4. wellnessTimer start method is invoked 5. wellnessTimer_Elapsed event handler is invoked 6. wellnessTimer stop method is invoked 7. wellnessTimer interval is set to 5 minutes 8. invocationTimer start method is invoked 9. 30 seconds later, the invocationTimer_Elapsed method is invoked 10. invocationTimer stop method is invoked
在这一点上,这两个定时器应该仍然存在,但应该被禁用。 我通过在Visual Studio 2010中进行附加debugging,并标记传递给事件处理程序的对象(发件人)的ID。 它和实例是同一个对象。 此外,本地窗口中的两个定时器都将其启用的属性设置为false。
这使得我不正确地使用inheritance,或者线程正在进行。 我不是那些最好的,但如果是由于他们,请让我知道,所以我可以学习。
感谢大家提前。
编辑#2:这是一些跟踪数据…
“o”表示传递给事件处理程序的对象
ABCService() method invoked <-- ABCService() method invoked --> Service1() method invoked <-- Service1() method invoked --> OnStart() method invoked <-- OnStart() method invoked --> wellnessTimer_Elapsed() method invoked <-- ((System.Timers.Timer) o).Enabled = False ((System.Timers.Timer) o).Interval = 5000 this.wellnessTimer.Enabled = False this.wellnessTimer.Interval = 5000 wellnessTimer_Elapsed() method invoked --> invocationTimer_Elapsed() method invoked <-- ((System.Timers.Timer) o).Enabled = False ((System.Timers.Timer) o).Interval = 30000 this.invocationTimer.Enabled = False this.invocationTimer.Interval = 30000 invocationTimer_Elapsed() method invoked --> wellnessTimer_Elapsed() method invoked <-- ((System.Timers.Timer) o).Enabled = False ((System.Timers.Timer) o).Interval = 60000 this.wellnessTimer.Enabled = False this.wellnessTimer.Interval = 60000 wellnessTimer_Elapsed() method invoked --> invocationTimer_Elapsed() method invoked <-- ((System.Timers.Timer) o).Enabled = False ((System.Timers.Timer) o).Interval = 30000 this.invocationTimer.Enabled = False this.invocationTimer.Interval = 30000 invocationTimer_Elapsed() method invoked -->
从MSDN对Timer类的评论 :
已调用Dispose或Stop方法之后或Enabled属性设置为false之后可能发生已消逝的事件,因为引发Elapsed事件的信号始终在线程池线程上排队等待执行。 解决这种竞争条件的一种方法是设置一个标志,告诉Elapsed事件的事件处理程序忽略后续事件。
所以你可以在你的事件处理程序中这样做,以防止在定时器被禁用之后执行它:
private static void OnTimedEvent(object source, ElapsedEventArgs e) { if (timer.Enabled) { Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime); } }
您是否完全按照您提供的代码来体验问题,还是依赖于代码:
// depending on logic, these next two lines will be called together or not at all
根据我从代码中读取的内容,当在onCreated调用中遇到错误时,健康计时器将每隔60秒触发一次。 如果这是在执行文件操作,那么尖叫的一件事就是服务运行的帐户的安全权限。
捕捉异常时,将其输出到事件日志或日志文件。 异常行为很容易导致混淆,尤其是在连接调试器不太方便的情况下。