在 Windows 服务停止时优雅地关闭前台线程
在我的 Windows 服务中,我创建了一个“父”前台线程,该线程又使用 ThreadPool(这意味着它们是后台)生成“子”线程来执行任务。
在 Windows 服务停止时优雅地关闭前台线程的最佳方法是什么?
这是我当前的实现(剥离了特定于任务的逻辑):
public partial class TaskScheduler : ServiceBase
{
private static AutoResetEvent _finishedTaskAutoResetEvent = new AutoResetEvent(false);
//This flag is used to increase chances of the Spawning Thread to finish gracefully when service stops.
private bool StopRequested { get; set; }
private int _executingTasksCount;
private int ExecutingTasksCount { get { return _executingTasksCount; } }
private void IncCurrentTasksCount()
{
Interlocked.Increment(ref _executingTasksCount);
}
private void DecCurrentTasksCount()
{
Interlocked.Decrement(ref _executingTasksCount);
}
public TaskScheduler()
{
InitializeComponent();
Thread spawningThread = new Thread(DoSpawnTaskExecutionThreads);
spawningThread.Name = "Spawning Thread";
spawningThread.IsBackground = false;
spawningThread.Start();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
StopRequested = true;
}
private void DoSpawnTaskExecutionThreads()
{
//We check StopRequested to try and finish this thread gracefully when service stops.
while (!StopRequested)
{
while (!StopRequested && ExecutingTasksCount < MaxPooledTasks)
{
ThreadPool.QueueUserWorkItem(ExecuteTask, new Task());
IncCurrentTasksCount();
}
_finishedTaskAutoResetEvent.WaitOne();
}
//Either all task execution threads will finish or the process will be terminated forcibly.
while (ExecutingTasksCount > 0)
{
Thread.Sleep(200); //Check five times a second.
}
_eventLog.WriteEntry("The Spawning Thread finished along with task execution threads.");
}
private void ExecuteTask(object state)
{
try
{
Task task = (Task)state;
task.Execute();
}
catch
{
// Handle exception.
}
finally
{
DecCurrentTasksCount();
_finishedTaskAutoResetEvent.Set();
}
}
}
In my windows service I create one "parent" foreground thread that in turn spawns "child" threads using ThreadPool (which means they are background) to execute tasks.
What is the best way to close foreground thread gracefully on windows service stop?
Here is my current implementation (stripped out of task-specific logic):
public partial class TaskScheduler : ServiceBase
{
private static AutoResetEvent _finishedTaskAutoResetEvent = new AutoResetEvent(false);
//This flag is used to increase chances of the Spawning Thread to finish gracefully when service stops.
private bool StopRequested { get; set; }
private int _executingTasksCount;
private int ExecutingTasksCount { get { return _executingTasksCount; } }
private void IncCurrentTasksCount()
{
Interlocked.Increment(ref _executingTasksCount);
}
private void DecCurrentTasksCount()
{
Interlocked.Decrement(ref _executingTasksCount);
}
public TaskScheduler()
{
InitializeComponent();
Thread spawningThread = new Thread(DoSpawnTaskExecutionThreads);
spawningThread.Name = "Spawning Thread";
spawningThread.IsBackground = false;
spawningThread.Start();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
StopRequested = true;
}
private void DoSpawnTaskExecutionThreads()
{
//We check StopRequested to try and finish this thread gracefully when service stops.
while (!StopRequested)
{
while (!StopRequested && ExecutingTasksCount < MaxPooledTasks)
{
ThreadPool.QueueUserWorkItem(ExecuteTask, new Task());
IncCurrentTasksCount();
}
_finishedTaskAutoResetEvent.WaitOne();
}
//Either all task execution threads will finish or the process will be terminated forcibly.
while (ExecutingTasksCount > 0)
{
Thread.Sleep(200); //Check five times a second.
}
_eventLog.WriteEntry("The Spawning Thread finished along with task execution threads.");
}
private void ExecuteTask(object state)
{
try
{
Task task = (Task)state;
task.Execute();
}
catch
{
// Handle exception.
}
finally
{
DecCurrentTasksCount();
_finishedTaskAutoResetEvent.Set();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我发现代码存在一些问题。
StopRequested
的检查不是线程安全的。ExecutingTaskCount
的检查不是线程安全的。_finishedTaskAutoResetEvent
是一个AutoResetEvent
信号可能会丢失,因为WaitHandle
不维护计数。也许这就是您想要的,但它可能会导致嵌套while
循环出现一些奇怪的旋转。这是我重构您的代码的方法。它使用 .NET 4.0 中提供的 CountdownEvent 类。
I see a couple of problems with the code.
StopRequested
is not thread-safe.ExecutingTaskCount
is not thread-safe._finishedTaskAutoResetEvent
is anAutoResetEvent
signals can get lost because thatWaitHandle
does not maintain a count. Maybe that is what you want, but it could result in some strange spinning of the nestedwhile
loops.Here is how I would refactor your code. It uses the
CountdownEvent
class which is available in .NET 4.0.我在这里看到一个问题:
StopRequested 不应该是一个自动属性。您应该将其定义为带有支持字段的属性,以便将其标记为 不稳定。
如果没有这个,当服务设置退出条件时,线程可能看不到(至少立即)。
此外,如果可以选择 .NET 4,则可以使用 CancellationToken 和 BlockingCollection来完成更简单的设计。
There is one issues I see here:
StopRequested should not be an automatic property. You should define this as a property with a backing field, in order to mark it volatile.
Without this, it's possible that the exit condition may not be seen (at least right away) by your thread when it's set by the service.
Also, if .NET 4 is an option, there are much simpler designed that could be done using
CancellationToken
andBlockingCollection<T>
.您可以使用 Join 方法“优雅地”终止线程。 MSDN 有一些有关该方法的信息。
You can use the Join method to "gracefully" kill the thread. MSDN has some information about the method.