我已经阅读了很多与Windows服务和定时器使用相关的帖子,但我没有找到任何理由仍然触发我的事件处理程序。有人能指出我正确的方向吗?我想知道为什么这种情况正在发生,所以我明白将来如何避免这种情况。
编辑:永远不会调用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中的进程调试了这个,并标记了传递给事件处理程序的对象(发送者)的ID。它与实例是同一个对象。此外,Locals窗口中的两个计时器都将其enabled属性设置为false。
这让我觉得我正在使用继承错误,或者正在进行线程化。我不是最好的,但如果是因为它们,请告诉我,以便我可以学习。
提前感谢所有人。
编辑#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 -->
答案 0 :(得分:1)
来自MSDN's remarks on the Timer class:
在调用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);
}
}
答案 1 :(得分:0)
您是否遇到了与您提供的代码完全相同的问题,或者它是否依赖于代码:
// depending on logic, these next two lines will be called together or not at all
根据我从代码中读到的内容,健康计时器会在遇到onCreated调用错误时每隔60秒触发一次。如果这是在进行文件操作,那么尖叫的一件事就是服务运行的帐户的安全权限。
捕获异常时,将其输出到事件日志或日志文件。异常行为很容易导致混乱的情况,尤其是在连接调试器不太方便的情况下。