代码之家  ›  专栏  ›  技术社区  ›  Otávio Décio

尝试/捕获和线程

  •  13
  • Otávio Décio  · 技术社区  · 15 年前

    我知道原因,但我想问一下,是否有人能够很好地理解为什么线程内部引发的异常从未被启动它的代码捕获。下面是一些非常简单的代码来演示我的意思:

    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);
                }
            }
        }
    }
    

    我天真地认为通过尝试/抓捕我是安全的,但我发现困难的是事实并非如此(它破坏了我的一项服务)。

    5 回复  |  直到 14 年前
        1
  •  28
  •   Jon Skeet    15 年前

    一般来说,在新线程中抛出异常时,您不知道起始线程将在哪里——为什么它会等待线程抛出异常?

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

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

        2
  •  2
  •   John Saunders    15 年前

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

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

        3
  •  2
  •   Kibbee    15 年前

    在Try/Catch语句中不会捕获正在运行的线程,因为它正在另一个线程中运行。Try/Catch仅适用于当前线程。您需要做的是在线程正在运行的函数中使用try/catch,并有一些方法来管理发生崩溃时会发生什么。

        4
  •  2
  •   48klocs    15 年前

    您可能需要使用 EventGeneratingThread wrapper -这将允许您捕获并处理从生成线程的进程中抛出的异常。

        5
  •  2
  •   Iggy    14 年前

    试着在你的嫁妆前加上这个

    <System.Diagnostics.DebuggerNonUserCodeAttribute()> _
    

    我使用的是后台工作程序,而我循环中的所有try-catch都按照您期望的那样工作。