2010-02-22 165 views
8

我想爲我的C#應用​​程序編寫一個ThreadManager。我創建了幾個線程:
我的文本編寫器的一個線程。
一個線程監視一些統計信息。
多線程執行大量計算(每個核心最多4個線程,並且我在2x四核服務器上運行我的應用程序)。關閉多線程應用程序

我的應用程序一次最多可以運行24小時,因此所有線程都會在開始時創建,並且始終保持應用程序運行的整個時間。

我希望有一個地方可以「註冊」我所有的步驟,當應用程序關閉時,我只需調用一個方法,它會遍歷所有已註冊的線程並關閉它們。

出於這個目的,我設計了以下類:

public class ThreadManager 
{ 
    private static Object _sync = new Object(); 
    private static ThreadManager _instance = null; 
    private static List<Thread> _threads; 
    private ThreadManager() 
    { 
     _threads = new List<Thread>(); 
    } 

    public static ThreadManager Instance 
    { 
     get 
     { 
      lock (_sync) 
      { 
       if (_instance == null) 
       { 
        _instance = new ThreadManager(); 
       } 
      } 
      return _instance; 
     } 
    } 

    public void AddThread(Thread t) 
    { 
     lock (_sync) 
     { 
      _threads.Add(t); 
     } 
    } 

    public void Shutdown() 
    { 
     lock (_sync) 
     { 
      foreach (Thread t in _threads) 
      { 
       t.Abort(); // does this also abort threads that are currently blocking? 
      } 
     } 
    } 
} 

我想確保我的所有線程都殺了那麼應用程序可以正常關閉,並在某些運算的中間關停就好了太。我應該知道這裏有什麼嗎?鑑於我的情況,這種方法是否合適?

+0

哇! Lot很好的答案...現在很難選擇。因爲他是第一個,所以我給了Nate複選標記,把它從他身上拿走是不公平的。讓我們看看這些票是怎麼說的。我從你的答案中得到一些有用的東西,所以請投票支持你的心。 – Kiril 2010-02-22 23:06:41

+0

線程池線程的默認行爲與我所建議的相同。如果你不關心你的線程沒有完成,我的是最簡單的解決方案。很明顯,其他答案在管理線程方面做得很好,但是你明確指出在計算過程中殺死線程是很好的。 – 2010-02-22 23:14:52

+0

我同意你的看法;),我不打算取消選中標記,因爲這樣做不公平,你給了我最準確,最快速,最簡單的答案......我希望其他人得到他們的公平信用,所以我希望每個人都爲所有的好答案投票。 – Kiril 2010-02-23 00:04:27

回答

16

如果將線程設置爲後臺線程,它們將在應用程序關閉時被終止。

myThread.IsBackground = true; 

顯然,如果您需要線程在關機前完成,這不是您想要的解決方案。

+0

謝謝Nate,當我創建它們時,我將所有線程設置爲後臺線程......這是否意味着我不需要中止它們呢? – Kiril 2010-02-22 22:56:20

+0

是的,如果它們被設置爲後臺線程,關閉應用程序將強制線程退出。 http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx – 2010-02-22 22:57:58

14

中止線程是你所做的當所有其他都失敗。這是一件危險的事情,你應該只做最後的手段。執行此操作的正確方法是製作線程邏輯,以便每個工作線程在主線程向其發出關閉命令時快速正確地響應。

巧合的是,這是我本週博客的主題。

http://blogs.msdn.com/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx

+1

線程中止異常在執行finally塊期間被阻止對我而言是新的。感謝您添加此。 – 2010-02-22 23:13:47

+0

@ fatcat1111:事實上,沒有任何事情可以保證中止的線程將因中止而停止。只是另一個避免Thread.Abort的原因;它既危險又不可靠。 – 2010-02-22 23:37:49

+0

同意,絕對是最後的選擇。 – 2010-02-23 00:54:54

3

如果什麼AddThread您關閉正在運行時叫什麼名字?

當關閉完成時,在AddThread中等待的線程將向集合中添加一個新線程。這可能會導致您的應用程序停滯不前。

添加一個您在關機時只設置的布爾標誌,以防止出現這種情況。

bool shouldGoAway = false; 
public void AddThread(Thread t) 
{ 
    lock (_sync) 
    { 
     if(! shouldGoAway) 
      _threads.Add(t); 
    } 
} 

public void Shutdown() 
{ 
    lock (_sync) 
    { 
     shouldGoAway = true; 
     foreach (Thread t in _threads) 
     { 
      t.Abort(); // does this also abort threads that are currently blocking? 
     } 
    } 

此外,你不應該使用靜態成員 - 沒有理由因爲你有你的單身實例。

.Abort()不會中止在非託管空間中阻塞的線程。所以如果你這樣做,你需要使用其他一些機制。

1

如果你不關心的工作線程狀態,則可以遍歷_Thread並中止:

void DieDieDie() 
{ 
    foreach (Thread thread in _thread) 
    { 
     thread.Abort(); 
     thread.Join(); // if you need to wait for the thread to die 
    } 
} 

在你的情況,你可能只需要中止所有這些,關機,因爲他們只是在做計算。但是,如果您需要等待數據庫寫入操作或需要關閉非託管資源,那麼您需要捕獲ThreadAbortException或指示線程自我犧牲自己。

0

你想延遲線程取消,這基本上意味着線程終止自己,而不是線程管理器異步取消線程,這是更加不明確和危險。

我想要比直接終止更優雅地處理線程取消,您可以使用由線程之外的事件觸發的信號處理程序 - 也許由您的線程管理器來處理。