在我的Windows服務中,我創建了一個「父」前臺線程,它使用ThreadPool(這意味着它們是後臺)產生執行任務的「子」線程。在windows服務上優雅地關閉前臺線程
在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();
}
}
}
感謝您提供如此詳盡的解釋和示例代碼。我有一些問題: 1)「ExecutingTaskCount的檢查不是線程安全的」:爲什麼?我只是用Interlocked類修改它。如果因爲某種原因我仍然想使用它,我會怎麼做呢? 你什麼時候會推薦使用Interlocked類? 2)「... _finishedTaskAutoResetEvent是一個AutoResetEvent信號可能會因爲WaitHandle不保持計數而丟失......」:這種情況的原因是什麼?任務拋出一個未處理的異常,我因爲某種原因沒有處理它? – Den 2010-10-26 15:39:25
RE#1 ...爲了讓'ExecutingTasksCount'線程安全,您將必須執行'_executingTasksCount'的volatile讀取。這可以使用'Interlocked.CompareExchange'方法或將變量標記爲'volatile'來完成。 – 2010-10-26 17:58:43
RE#2 ...想象一下在DecCurrentTasksCount和_finishedTaskAutoResetEvent.Set之間所有任務線程都被搶佔的假想場景(非常不可能)。我認爲你的嵌套循環可以防範任何問題,但我想象的是他們可以表現的奇怪方式。再次,我認爲這種方法實際上沒有任何問題,但很難去思考。 – 2010-10-26 18:10:44