В моей службе 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();
}
}
}