我正在构建一个 Windows 服务基类来管理对任何挂起任务的调度表的轮询和运行它们。
Windows 服务正在使用System.Timers.Timer
启动计划的表轮询。
ThreadPool.SetMaxThread
在初始化计时器之前,我将其设置为 10。
protected override void OnStart(string[] args)
{
ThreadPool.SetMaxThreads(10, 10);
this._Timer = new System.Timers.Timer();
this._Timer.Elapsed += new ElapsedEventHandler(PollWrapper);
this._Timer.Interval = 100;
this._Timer.Enabled = true;
}
计时器调用的委托方法保持运行线程的计数,以便可以在 OnStop() 方法中使用它来等待每个线程完成,然后再释放服务。
private void PollWrapper(object sender, ElapsedEventArgs e)
{
numberOfRunningThreads++;
try
{
this.Poll(sender, e);
}
catch (Exception exception)
{
//some error logging here
}
finally
{
numberOfRunningThreads--;
}
}
protected override void OnStop()
{
this._Timer.Enabled = false;
while (numberOfRunningThreads > 0)
{
this.RequestAdditionalTime(1000);
Thread.Sleep(1000);
}
}
通常,当我尝试从 Windows 服务管理控制台停止服务时,该服务不会停止。如果我调试它并向 OnStop() 方法添加断点,我可以看到这不是因为 numberOfRunningThreads 卡在大于 0 的数字上(通常远大于 10!)。没有任务正在运行,它永远保持在那个数字上!
首先,我不明白这个数字怎么会大于 10,尽管ThreadPool.SetMaxThreads
应该将其限制为 10?
其次,即使我没有设置最大线程数,我希望 PollWrapper 的 finally 块最终会将计数带回 0。如果计数器保持大于 0,则只能用 finally 块来解释执行,对吧!?这怎么可能?
最后,您是否会建议一种不同的方法来将轮询限制为固定数量的可能并发运行线程(.NET 3.5)?
非常感谢。
更新:
在阅读了 Yahia 关于可重入性和 SetMaxThread 的评论后,我修改了 PollWrapper,使其始终限制生成的运行线程的最大数量。我仍然会确保 Poll 是可重入的。
private void PollWrapper(object sender, ElapsedEventArgs e)
{
lock(this)
{
if(this.numberOfRunningThreads < this.numberOfAllowedThreads)
{
this.numberOfRunningThreads++;
Thread t = new Thread(
() =>
{
try
{
this.Poll(sender, e);
}
catch (Exception ex)
{
//log exception
}
finally
{
Interlocked.Decrement(ref this.numberOfRunningThreads);
}
}
);
t.Start();
}
}