您正在寻找的是能够响应两个不同事件的通知 - (1) 计时器到期时和 (2) 服务停止时。 @Anurag Ranhjan 与WaitHandle 走在正确的轨道上,但是您有两个事件,而不是一个。要正确处理此问题,请执行以下操作。
首先,使用ManualResetEvent 定义您关心的两个事件。如果您愿意,可以使用AutoResetEvent;我只是更喜欢手动重置事件。
using System.Threading;
ManualResetEvent shutdownEvent = new ManualResetEvent();
ManualResetEvent elapsedEvent = new ManualResetEvent();
您需要在这些事件发生时触发它们。对于shutdownEvent,这很容易。在您的 Windows 服务的 OnStop 回调中,只需设置事件即可。
protected override void OnStop
{
shutdownEvent.Set();
}
对于elapsedEvent,您可以通过几种不同的方式执行此操作。您可以创建一个使用Thread.Sleep 的后台线程,即ThreadPool。当线程唤醒时,设置elapsedEvent 并重新进入睡眠状态。由于它是后台线程,因此它在关闭时不会挂起您的服务。正如您已经建议的那样,替代方法是使用计时器。我就是这样做的。
using System.Timers;
Timer timer = new Timer();
timer.Interval = 5000; // in milliseconds
timer.Elapsed += delegate { elapsedEvent.Set(); };
timer.AutoReset = false; // again, I prefer manual control
timer.Start();
既然您已经正确设置了事件,请将它们放入 WaitHandle 数组中。
WaitHandle[] handles = new WaitHandle[]
{
shutdownEvent,
elapsedEvent
};
代替WaitHandle.WaitOne 方法,在while 循环中使用WaitHandle.WaitAny 方法,如下所示。
while (!shutdownEvent.WaitOne())
{
switch (WaitHandle.WaitAny(handles))
{
case 0: // The shutdownEvent was triggered!
break;
case 1: // The elapsedEvent was triggered!
Process(); // do your processing here
elapsedEvent.Reset(); // reset the event manually
timer.Start(); // restart the timer manually
break;
default:
throw new Exception("unexpected switch case");
}
}
我从我的项目中的生产代码中浓缩了这个示例。我知道这种机制有效,但我可能在文章中遗漏了一些东西。如果您有任何问题,请告诉我。