2011-03-07 168 views
6

每當我的ThreadPool中的線程拋出異常,我的代碼似乎卡在線程函數內的catch塊。我如何獲得例外回到主線程?C#ThreadPool QueueUserWorkItem異常處理

+1

可能重複的[如何從一個ThreadPool.QueueUserWorkItem捕獲異常?](http://stackoverflow.com/questions/753841/how-to-catch-exceptions-from-a-threadpool-queueuserworkitem) – Henrik 2011-03-07 09:49:16

+0

Duplicate: http://stackoverflow.com/questions/753841/how-to-catch-exceptions-from-a-threadpool-queueuserworkitem – Nick 2011-03-07 09:47:39

+0

這些方法不工作。我得到一個異常說'調用線程必須是STA,因爲許多UI組件需要這個。 ' – Aks 2011-03-07 09:51:32

回答

4

最好的做法是你的後臺線程不應該拋出異常。讓他們自己處理他們的例外。

理想情況下,您應該將代碼包裝在您的方法中,該代碼在try-catch塊中的線程上執行,並處理catch塊中的異常。不要將它從catch塊中重新扔掉。

閱讀此瞭解更多詳情。 http://www.albahari.com/threading/#_Exception_Handling

如果要從後臺線程更新UI,可以使用Control.InvokeRequired屬性和Control.Invoke方法來實現。有關詳細信息和示例,請參閱MSDN鏈接。

+0

但我的用戶界面必須顯示異常。我能做什麼? – Aks 2011-03-07 09:56:33

+0

@Aks - 請參閱最新的答案。 – 2011-03-07 10:02:12

+1

在線程中捕獲它並使用隊列(管道)將消息發送回UI線程以顯示錯誤。線程邊界上的例外是一件壞事,很難排除難題。 – 2011-03-07 10:04:15

4

無法將異常從一個線程轉移到另一個線程。你可以做的是建立了一些同步機制來傳輸線程之間的異常信息,然後從目標線程像拋出一個新的異常:

class Program 
{ 
    Exception _savedException = null; 
    AutoResetEvent _exceptionEvent = new AutoResetEvent(false); 

    static void Main(string[] args) 
    { 
     Program program = new Program(); 
     program.RunMain(); 
    } 

    void RunMain() 
    { 
     ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod)); 

     while (true) 
     { 
      _exceptionEvent.WaitOne(); 
      if (_savedException != null) 
      { 
       throw _savedException; 
      } 
     } 
    } 

    void ThreadMethod(object contxt) 
    { 
     try 
     { 
      // do something that can throw an exception 
     } 
     catch (Exception ex) 
     { 
      _savedException = ex; 
      _exceptionEvent.Set(); 
     } 
    } 
} 

如果你有一個雙贏的形式應用的東西要簡單得多。在線程的catch子句中,使用表單的Invoke(或BeginInvoke)方法,爲它提供異常詳細信息。在使用Invoke啓動的方法中,您可以根據需要重新拋出或處理異常。