在C#线程中抛出异常

6
我有一个线程,就像这样,看了这个例子之后 链接文本
ThreadStart _threadStart = new ThreadStart(delegate()
{
       try
       {
           threadFunction(httpContext);
       }
       catch (Exception ex)
       {
           throw ex;
       }
 });
 Thread _thread = new Thread(_threadStart);
  _thread.Start();

当异常发生时,它不会在启动它的线程中重新抛出。那么我做错了什么或者该怎么做呢?
注意:提前感谢所有评论。

6
请注意,你绝不能像你在那里所做的那样重新抛出异常。在 catch 块中执行 throw; 就足够了... - Joey
我知道,但我抛出一个继承自“System.Exception”的自定义异常,并带有消息。 - Hiyasat
1
你需要使用所需的信息抛出一个新的异常。将原始异常作为InnerException传递。只有在添加的信息具有很高的价值时才这样做,因为它会使故障排除变得更加困难。 - Hans Passant
6个回答

8

异常将被抛出,但这只会结束线程。该异常不会在启动它的线程中重新抛出。


为什么会这样?最好的解决方案是什么? - Hiyasat
1
@Hiyasat:如果一个线程在任何时间都可以在其启动线程中抛出任何异常,那么实现起始线程来处理该异常将非常困难。您必须像发送任何其他结果一样将异常传递回启动线程,例如使用两个线程都可以访问的变量。 - Guffa

6
我认为问题的核心是理解:在线程内发生的异常不会传递给调用线程进行处理。
例如,假设您有一个叛逆的方法:
private static void RebelWithoutACause()
{
    throw new NullReferenceException("Can't touch this!");
}

假设您在程序中创建了一个新线程,并调用了此方法,作为一个谨慎的程序员,您决定将工作包装在try/catch块中:
private static void Main(string[] args)
{
    try
    {
        var thread = new Thread(RebelWithoutACause);
        thread.Start();
        thread.Join();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

然而,如果您在调试器中运行此代码,您会发现永远不会进入catch块,相反线程将被终止,并且调试器将抱怨您有未处理的异常。
您需要选择如何处理异常,但处理需要发生在每个线程入口方法内部。典型的处理包括记录详细信息,通过UI通知用户,并尽可能优雅地关闭应用程序。

2

你确定异常已经抛出了吗?如果一个线程由于异常失败,整个应用程序都会崩溃,可以使用AppDomain.CurrentDomain.UnhandledException事件来发现这种情况(请注意,当事件触发时,您无法阻止应用程序被结束,但可以清理资源并保存重要数据 - 有关事件文档,请参见更多信息)。

但是,引用你提到的线程的接受的答案,它说:

任何引发顶级异常的线程都表示存在严重问题。

你应该尝试记录异常和/或通知其他线程这个线程已经失败了。


1

异常已经被抛出了,只不过我猜你没有看到,因为它是在另一个线程上抛出的。因此,UI 线程(或者调用其他线程的任何线程)无法捕获异常,因为它看不到。

如果你将异常记录到文件中,我相信你会看到它的。:)


无论在哪个线程上引发异常,都会看到异常。我认为根本没有异常——线程只是正常结束了。 - Sergey Berezovskiy
我确定发生了异常,但它没有抛到主线程。 - Hiyasat

0

谢谢,但我在.NET 4任务中找到了更强大的东西。http://blogs.msdn.com/b/pfxteam/archive/2009/05/31/9674669.aspx - Hiyasat
谢谢提供链接-任务看起来很棒,我还没来得及查看。 - antsyawn

0
也许可以像这样做:
   const int numThreads = 8;
   Thread[] threads = new Thread[numThreads];
   Exception[] threadsExceptions = new Exception[numThreads];
   for (int i = 0; i < numThreads; i++) {
       threadsExceptions[i] = null;
       int closureVariableValue = i;
       ThreadStart command = () =>
       {
           try
           {
               throw new ArgumentException("thread_" + closureVariableValue + "'s exception");
           }catch(Exception any)
           {
               threadsExceptions[closureVariableValue] = any;
           }
       };
       threads[i] = new Thread(command);
       threads[i].Start();
   }
   for(int i = 0; i < numThreads; i++)
   {
       threads[i].Join();
       if (threadsExceptions[i] != null)
       {
           throw threadsExceptions[i];
       }
   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接