【问题标题】:Try/Catch and threadingTry/Catch 和线程
【发布时间】:2009-04-22 17:57:06
【问题描述】:

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

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 我会很安全,但我发现事实并非如此(它使我的一项服务崩溃)。

【问题讨论】:

  • 奇怪了,我刚才也准备发一个类似的帖子了。
  • 我确定我有异常冒泡到调用线程。虽然我没有使用线程池。只是 Thread T = new Thread(new ThreadStart( delegate() { Console.WriteLine("Crash !"); DoCrashyThingy(); } )); T.Start();
  • 我很容易错了,我的大部分工作都是这个可怕的单线程庞然大物..

标签: c# multithreading try-catch


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢,乔恩。令我困惑的是,它实际上使父进程崩溃;我想线程至少应该平静地死去,而不是把所有东西都带走。
  • 不 - 关键是意外的异常很可能表明某些事情严重错误,快速失败通常是一个更好的主意。这是 .NET 2.0 的新行为。见msdn.microsoft.com/en-us/library/ms228965.aspx
  • 所以我会得出结论,任何排队到线程队列中的代码块都必须完全包含在 try/catch 块本身中,这是最佳实践吗?我有一项服务,我不想仅仅因为它的一个线程出现问题而停止服务......
  • 最好的做法是捕捉并处理那些你理解的异常,让那些你没有关闭系统的异常,以免你的数据处于未知状态。这就是为什么如果允许未处理的异常冒泡超过调用堆栈的顶部,2.0 CLR 会终止您的应用程序。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 顺便说一句,我讨厌这句话,因为它忽略了我们需要假设才能生存的现实。这句话应该是指理解你的假设是什么并确定它们不正确的地方。
      【解决方案5】:

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

      <System.Diagnostics.DebuggerNonUserCodeAttribute()> _
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-12-14
        • 2014-11-27
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 2011-10-26
        • 2011-11-28
        相关资源
        最近更新 更多