如何确保Windows服务定时器产生的线程在停止Windows服务后完成执行?
问题描述:
我正在使用System.Timers.Timer
构建Windows服务。计时器委托计算的任务可能需要几秒到几分钟。我想确保当服务停止时,所有委派的线程在处理之前都处于完成状态。如何确保Windows服务定时器产生的线程在停止Windows服务后完成执行?
这是代码,但是它没有达到我期望的效果,因为如果Windows服务在运行时停止,当前运行的线程永远不会完成。
public abstract class AgentServiceBase : ServiceBase
{
private System.ComponentModel.IContainer components = null;
private System.Timers.Timer _Timer;
private string _logPath;
private const int MAXNUMBEROFTHREADS = 10;
protected int interval = 25000;
protected int numberOfAllowedThreads = 2;
public AgentServiceBase()
{
this.InitializeComponent();
this._logPath = (Path.GetDirectoryName(Assembly.GetAssembly(this.GetType()).CodeBase)).Substring(6).Replace("/", @"\");
}
protected override void OnStart(string[] args)
{
if (args.Length > 0)
{
int.TryParse(args[0], out interval);
}
if (args.Length > 1)
{
int.TryParse(args[1], out numberOfAllowedThreads);
if (numberOfAllowedThreads > MAXNUMBEROFTHREADS)
{
numberOfAllowedThreads = MAXNUMBEROFTHREADS;
}
if (numberOfAllowedThreads == 1)
{
numberOfAllowedThreads = 2;
}
}
ThreadPool.SetMaxThreads(numberOfAllowedThreads, numberOfAllowedThreads);
this._Timer = new System.Timers.Timer();
this._Timer.Elapsed += new ElapsedEventHandler(PollWrapper);
this._Timer.Interval = this.interval;
this._Timer.Enabled = true;
}
protected override void OnStop()
{
this._Timer.Enabled = false;
Process currentProcess = Process.GetCurrentProcess();
foreach (Thread t in currentProcess.Threads)
{
t.Join();
}
}
/// <summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = "Agent Service - Johnhenry";
}
private void PollWrapper(object sender, ElapsedEventArgs e)
{
try
{
this.Poll(sender, e);
}
catch (Exception exception)
{
string message = this.GetType().FullName + " - Windows Service Exception\n";
message += exception.GetNestedExceptionInSingleStringOutput();
FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY);
}
}
protected abstract void Poll(object sender, ElapsedEventArgs e);
}
非常感谢,
朱塞佩
UPDATE:
与计数当前进程的自己的线程我最终与使用计数器的简单的解决方案解决一些不同的尝试之后计时器启动的线程仍在运行。基于此,我在主线程上调用Sleep
并发出RequestAdditionalTime
,直到所有线程都结束。 按照修订后的2种方法:
protected override void OnStop()
{
this._Timer.Enabled = false;
while (numberOfRunningThreads > 0)
{
this.RequestAdditionalTime(1000);
Thread.Sleep(1000);
}
}
private void PollWrapper(object sender, ElapsedEventArgs e)
{
numberOfRunningThreads++;
try
{
this.Poll(sender, e);
}
catch (Exception exception)
{
string message = this.GetType().FullName + " - Windows Service Exception\n";
message += exception.GetNestedExceptionInSingleStringOutput();
FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY);
}
finally
{
numberOfRunningThreads--;
}
}
答
你可以通过调用RequestAdditionalTime
只要你的线程都没有在你的实现OnStop
环内完成了这项工作,但(前和/或调用后实现这一目标Join()
)。
但要注意 Windows可以会不耐烦并决定杀死你的Windows服务 - 例如关闭期间...
欲了解更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.aspx
的MSDN参考理想的情况下,我想推迟停止不超过所需的时间。我假设通过使用RequestAdditionalTime我需要传递一个固定的时间。通过在循环中添加RequestAdditionalTime,它是否会累积每个挂起线程的额外时间?谢谢。 –
是的 - 它需要一个固定的时间(以毫秒为单位),它会相加,所以它取决于您对线程的剩余运行时间有一个很好的估计......要么在循环之前调用一次(使用值对于所有线程来说足够大),或者你可以在循环中调用它,只需一个足够一个线程完成的小值)... – Yahia