2011-04-05 78 views
1

我正在處理我的第一個涉及一些基本線程/並行性的Windows服務項目。到目前爲止它一直非常強烈,但我慢慢開始理解線程(我想我們會看到這個...)。等待線程在Windows服務中停止

我有一個Windows服務將包含2鬆散耦合的工作線程。線程A將從FTP服務器上下載文件,解壓/準備它們並保存到另一個目錄,其中線程B將有一個FileSystemWatcher監視。線程B將解析這些文件,對這些數據做許多事情,進行一些http調用,最後歸檔並從工作目錄中刪除這些文件。

我剛開始工作,現在我面臨的問題是如何等待線程A和線程B返回。我看着這個問題:Thread.Join on multiple threads with timeout並有一個想法。

問題是,如果我們等待x線程返回ax每秒的第二個超時,並且有足夠的線程,即使在正常操作下服務也可能顯示爲不響應(我在SCM抱怨之前讀取超時爲30秒,對?)。另外,如果我們通過跟蹤剩餘時間來解決這個問題,就像我們在線程上循環一樣,我們在工作集合開始處等待線程的時間越長,剩餘線程返回的時間就越短 - 最終如果線程足夠多,即使所有線程都在預期的時間內返回,服務仍將顯示爲無響應。

在這種情況下,我可能只是在14秒的時間內在A和B上加入thread.join,因爲我只有兩個工人,14秒似乎有足夠的時間返回兩個工人。

如果我有可變數量的工作線程(假設大於8)是否值得做這樣的事情?這會工作可靠嗎?

注意:不要使用以下內容 - 這是多層次上的一個壞主意。見答案

protected override void OnStop() 
    { 
     // the service is stopping - set the event 
     Worker.ThreadStopEvent.Set(); 

     // stop the threads 
     Parallel.ForEach(_workerThreads, t => 
     { 
      t.Join(new TimeSpan(0, 0, 28)); 
     }); 
    } 

回答

1

我建議,而不是使用超時爲每個線程,而不是你設置你的事件,然後定期用較短的超時做Join。一個極端的版本是:

Worker.ThreadStopEvent.Set(); 
Thread.Sleep(30000); // wait 30 seconds 
// Now try to Join each thread, with a very short (20 ms, maybe) timeout. 

這種做法最大的問題是,你將永遠等待30秒,即使所有的線程停止在五秒鐘。

你可以做一個更好的睡眠一秒鐘的循環,然後做檢查。然後,您可以跟蹤哪些線程已停止,並在所有線程停止時退出循環。

儘管如此,使用CountdownEvent可能是最好的選擇。每個線程在停止時都會發出信號,主線程將等待所有線程停止。 Wait方法允許你指定一個超時值。等待之後,您可以通過以非常短暫的超時呼叫Join來確定是否還有線程掛起。

+0

+1你的答案是最多方面的,並且是首先提到CountdownEvent,這似乎是要走的路。 – HAL9000 2011-04-05 22:34:31

1

您目前的方法可能無法正常工作 - 您無法控制多少個線程實際上創建了多少線程,並非所有線程連接都可以並行運行 - 這完全取決於這些任務如何在線程池上進行調度。最重要的是,它的效率非常低,因爲你產生的所有線程基本上都在等待。

如果這些工作線程沒有必須在服務關閉時完成的關鍵任務,我會讓它們成爲所有後臺線程 - 在這種情況下,您根本不必處理這個問題。

+0

+1優點 - 我一直忘記TPL使用ThreadPool,你永遠不知道它有多深 - gah信息超載! – HAL9000 2011-04-05 22:30:45

1

從技術上講,您不必等到線程完成(加入),而是直到他們完成報告。因此,您可以使用所有線程之間共享的CountdownEvent的實例並等待它。所有的線程將在finally塊來遞減事件:

void WorkerThread (object args) 
{ 
    try 
    { 
    // actual work here 
    ... 
    } 
    finally 
    { 
    sharedCountdown.Signal(); 
    } 
} 

和做停機和等待的線程結束時:

// Notify all workers of shutdown 
... 

// Now wait for all workers to complete, up to 30 seconds 
sharedCountdown.Wait(TimeSpan.FromSeconds(30)); 
+0

+1感謝您詳細介紹CountdownEvent方法。 – HAL9000 2011-04-05 22:32:37