2011-04-19 30 views
3

我有以下代碼片段。爲什麼在threadPool線程上引發異常不是由C#中的主線程處理的

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      Thread m_thread = new Thread(() => 
       { 
        //try 
        //{ 
         checkexc(); 
        //} 
        //catch (Exception ex) 
        //{ 

        //} 
       } 
       );    
      m_thread.Start(); 

     } 
     catch (Exception ex) 
     { 

     } 
    } 
    static void checkexc() 
    { 
     throw new NullReferenceException(); 
    } 
} 

NullReferenceException不被覆蓋的Try-Catch塊處理。但是,如果我包裝線程()構造函數內的委託,那麼它由Try-Catch處理。爲什麼沒有外Try-Catch處理這個異常。

+7

因爲它是不同的線程 – ColWhi 2011-04-19 09:51:40

回答

7

想象一下你有一條主要道路(A),另一條道路從那條道路(B)分支出去。

當一輛卡車駛向A時,如果它墜毀,那麼A將知道它,並且交通將停止。

當一輛卡車沿着B行駛時,如果它發生碰撞,那麼B將知道它,並且交通將停止。

但是通過什麼機制B會告訴A卡車已經撞上了它?

一旦卡車是B,它不影響A,除非有另一個入口點的A到B.

怎麼會在你的其他線程異常傳達給主線程?一旦另一個線程運行,它不再(直接)與主線程通信。

+0

是的,這是一個泄漏的抽象 – 2011-04-19 09:56:41

1

因爲異常沒有發生在線程構造函數中。僅在m_thread.Start()被調用並且它在另一個線程上執行後調用checkexc()。

0

正如其他人所說,「因爲它在不同的線程」。換句話說,爲什麼第一個線程會因爲另一個線程遭受異常而受到困擾呢?

如果使用BackgroundWorker,則在RunWorkerCompleted事件的參數中傳遞異常(線程完成時) - 以便根據您的情況更輕鬆地進行處理。

1

從另一角度來回答這個問題:

任務並行庫(TPL)確實手柄(抓&繁殖)爲您的例外。

但是,在您等待()任務完成的位置出現異常,而不是在啓動任務的點/線程處。

// No point in specifically surrounding the next 2 statements 
    Task t1 = Task.Factory.StartNew(() => Foo()); 
    Task t2 = Task.Factory.StartNew(() => Bar()); 

    try 
    { 
     Task.WaitAll(t1, t2); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); // Aggregated exceptions from Foo and/or Bar 
    } 

當使用Parallel.ForEach()代碼看起來像你因爲有責任(隱式爲WaitAll()在給ForEach的端部)。

1

作爲馬特的解釋細節,在子線程上拋出的異常不會冒泡到父線程。不過,如果你想成爲能夠從一個子線程捕獲異常,這裏是應該做的一種方式:

class Program { 
    static void Main(string[] args) { 
     Action action = BeginCheckExc; 
     IAsyncResult result = action.BeginInvoke(new AsyncCallback(EndCheckExc), null); 

     try { 
      action.EndInvoke(result); 
     } 
     catch (Exception ex) { // Exception is caught here 
      Console.WriteLine(ex.Message); 
     } 
    } 

    static void BeginCheckExc() { 
     Thread.Sleep(3000); // Simulate long operation 
     throw new Exception("Oops! Something broke!"); 
    } 

    static void EndCheckExc(IAsyncResult result) { 
     Console.WriteLine("Done"); 
     Console.ReadLine(); 
    } 
} 

您將看到的輸出是一樣的東西:

完成。

糟糕!有什麼東西壞了!

按任意鍵繼續......

0

如果您有興趣從您的所有線程捕獲未處理excptions,你可以添加一個應用廣泛的未處理的異常處理。看一看在文檔Application.ThreadException & AppDomain.UnhandledException

本質上講,你需要處理這個代碼是:

Application.ThreadException += new ThreadExceptionEventHandler(ThreadExceptionFunction); 
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionFunction); 

public static void ThreadExceptionFunction(object sender, ThreadExceptionEventArgs args) 
{ 
    // Handle the exception.   
} 

public static void UnhandledExceptionFunction(object sender, UnhandledExceptionEventArgs args) 
{ 
    // Handle the exception. 
} 

記住的異常後,您的應用程序可能會在一個腐敗狀態,記錄錯誤後最好立即退出。