2011-04-19 67 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. 
} 

记住的异常后,您的应用程序可能会在一个腐败状态,记录错误后最好立即退出。