14

我知道为什么,但我想问一下是否有人很好地理解了为什么线程内引发的异常永远不会被启动它的代码捕获。这是一些非常简单的代码来演示我的意思:

using System;
using System.Collections.Generic;
using System.Threading;

namespace TestCrash
{
    class Program
    {
        private static void Crash(object control)
        {
            AutoResetEvent are = (AutoResetEvent)(((object[])control)[0]);
            are.Set();
            throw new Exception("Burn baby burn");
        }
        static void Main(string[] args)
        {
            try
            {
                List<WaitHandle> waitHandles = new List<WaitHandle>();
                for (int i = 0; i < 100; i++)
                {
                    AutoResetEvent are = new AutoResetEvent(false);
                    waitHandles.Add(are);
                    object[] procControl = new object[] { are };
                    ThreadPool.QueueUserWorkItem(Crash, procControl);
                    WaitHandle.WaitAll(waitHandles.ToArray());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

我天真地认为通过 try/catch 我会很安全,但我发现事实并非如此(它正在使我的一项服务崩溃)。

4

5 回答 5

30

好吧,一般来说,在新线程中引发异常时,您不知道原始线程将在哪里 - 为什么它会等待线程抛出异常?

想想所涉及的堆栈 - 当抛出异常时,它会向上堆栈直到到达适当的 catch 块。新线程与创建线程有一个完全独立的堆栈,因此它永远不会到达创建线程堆栈中的 catch 块。

编辑:当然,您可以设计您的系统,以便创建线程确实等待其他事情发生 - 有点像 Windows 窗体应用程序中的消息循环。然后,新线程可以捕获异常并向创建线程发送消息,然后该线程可以处理异常。这不是正常的设置——你必须明确地做这一切。

于 2009-04-22T17:59:39.607 回答
4

正在运行的线程不会被您的 try/catch 语句捕获,因为它正在另一个线程中运行。Try/Catch 仅适用于当前线程。您需要做的是在线程运行的函数中使用 try/catch,并通过某种方式管理发生崩溃时发生的情况。

于 2009-04-22T18:00:34.487 回答
3

您可能想要使用EventGeneratingThread 包装器- 这将让您捕获并处理从产生它们的进程中抛出的线程中的异常。

于 2009-04-22T18:23:23.417 回答
2

做出假设是个坏主意,尤其是在涉及多个线程的情况下(你知道那句老话)。

为什么启动线程的代码看到异常?抛出异常时,启动线程的代码甚至可能不存在。

于 2009-04-22T17:59:54.690 回答
2

尝试在您的 DoWork Sub 之前添加它

<System.Diagnostics.DebuggerNonUserCodeAttribute()> _

我正在使用后台工作程序,并且循环中的所有 Try Catch 都可以按照您的预期工作。

于 2010-08-18T13:00:10.293 回答