概要:
在 Windows服务和控制台应用程序我正在调用一个公共库,其中包含定时器,定期触发大约需要30秒钟的操作.不过这样做很好
在 Windows服务和控制台应用程序我正在调用一个公共库,其中包含定时器,定期触发大约需要30秒钟的操作.不过这样做很好
当服务停止或应用程序退出被调用并且计时器在ElapsedEventHandler中时,我需要服务停止/应用程序退出等待直到事件处理程序完成.
我已经通过在调用定时器停止方法时检查一个Boolean InEvent属性来实现这个功能.
虽然这是功能,但问题是:这是最好的办法吗?是否有更好的方法可以更好地达到这个目的?
另一个问题是我需要避免服务停止请求失败,并显示“服务无法响应停止请求”
这是我的实现
public sealed class TimedProcess : Idisposable
{
static TimedProcess singletonInstance;
bool InEvent;
Timer processtimer;
private TimedProcess()
{
}
public static TimedProcess Instance
{
get
{
if (singletonInstance == null)
{
singletonInstance = new TimedProcess();
}
return singletonInstance;
}
}
public void Start(double interval)
{
this.processtimer = new Timer();
this.processtimer.AutoReset = false;
this.processtimer.Interval = interval;
this.processtimer.Elapsed += new ElapsedEventHandler(this.processtimer_Elapsed);
this.processtimer.Enabled = true;
}
public void Stop()
{
if (processtimer != null)
{
while (InEvent)
{
}
processtimer.Stop();
}
}
void processtimer_Elapsed(object sender,ElapsedEventArgs e)
{
try
{
InEvent = true;
// Do something here that takes ~30 seconds
}
catch
{
}
finally
{
InEvent = false;
processtimer.Enabled = true;
}
}
public void dispose()
{
if (processtimer != null)
{
Stop();
processtimer.dispose();
}
}
}
这就是在OnStart / console应用程序main中调用的方法:
TimedProcess.Instance.Start(1000);
这是在服务OnStop和应用程序main(挂起的按键)中如何调用:
TimedProcess.Instance.Stop();
解决方法
可能最简单和最可靠的方法是使用监视器.创建主程序和定时器回调可以访问的对象:
private object _timerLock = new object();
您的主程序在关闭之前尝试锁定:
// wait for timer process to stop Monitor.Enter(_timerLock); // do shutdown tasks here
你的定时器回调也锁定它:
void processtimer_Elapsed(object sender,ElapsedEventArgs e)
{
if (!Monitor.TryEnter(_timerLock))
{
// something has the lock. Probably shutting down.
return;
}
try
{
// Do something here that takes ~30 seconds
}
finally
{
Monitor.Exit(_timerLock);
}
}
主程序一经获取就不应该释放锁.
如果您希望主程序在一段时间后继续关闭,无论是否获得锁定,请使用Monitor.TryEnter.例如,这将等待15秒.
bool gotLock = Monitor.TryEnter(_timerLock,TimeSpan.FromSeconds(15));
如果能够获得锁,则返回值为true.
顺便问一下,我强烈建议您使用System.Threading.Timer而不是System.Timers.Timer.后者阻止例外,最终可能会隐藏错误.如果您的Elapsed事件发生异常,它将永远不会被转义,这意味着您永远不会知道它.有关更多信息,请参阅我的blog post.