多线程应用程序中的异常。

发布于 2024-10-30 14:20:01 字数 668 浏览 2 评论 0原文

我从一位非常有洞察力的人那里听说,线程中抛出(而不是捕获)的异常正在传播到父线程。这是真的吗? 我尝试过类似的操作,但无法捕获创建线程中的异常。

    static void Main(string[] args)
    {
        ParameterizedThreadStart pts = 
           new ParameterizedThreadStart(ThreadMethod);
        try
        {
            Thread t = new Thread(pts);
            t.Start(new object());
            Console.ReadLine();
        }
        catch (Exception ex) //the exception is not caught
        {
            Debugger.Break();
        }
    }


    static void ThreadMethod(object @object)
    {
        Thread.Sleep(2000);
        throw new IndexOutOfRangeException();
        Thread.CurrentThread.Abort();
    }

I have heard from a very discerning person that an exception being thrown (and not caught) in a thread is being propagated to the parent thread. Is that true?
I have tried something like this but couldn't catch the exception in the creating thread.

    static void Main(string[] args)
    {
        ParameterizedThreadStart pts = 
           new ParameterizedThreadStart(ThreadMethod);
        try
        {
            Thread t = new Thread(pts);
            t.Start(new object());
            Console.ReadLine();
        }
        catch (Exception ex) //the exception is not caught
        {
            Debugger.Break();
        }
    }


    static void ThreadMethod(object @object)
    {
        Thread.Sleep(2000);
        throw new IndexOutOfRangeException();
        Thread.CurrentThread.Abort();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

薔薇婲 2024-11-06 14:20:02

线程的异常不会传播到主线程的上下文。这确实很有意义——当抛出异常时,主线程通常处于与包含异常处理程序的范围完全不同的范围内。

您可以通过挂钩 AppDomain.UnhandledException。请参阅该页面了解详细信息,包括 Windows 窗体应用程序的差异等。

The thread's exception will not propogate to the main thread's context. This really makes sense - by the time the exception is thrown, the main thread will typically be in a completely different scope than the one containing your exception handler.

You can catch these exceptions (typically to log them) by hooking into AppDomain.UnhandledException. See that page for details, including differences in Windows Forms applications, etc.

凉宸 2024-11-06 14:20:02

不,不会的。为了捕获线程异常,您需要使用Application.ThreadException。

No, it won't. In order to catch thread exceptions you need to use Application.ThreadException.

鹿港小镇 2024-11-06 14:20:02

有关 C# 中线程的不错资源,其中有一个用于异常处理的部分:C# 中的线程

A decent resource on Threading in C# that has a section for exception handling: Threading in C#

苍白女子 2024-11-06 14:20:02

异常在调用堆栈中向上传播。

如果从某个方法启动一个新线程,它将向上传播,直到到达该方法。

如果该方法没有捕获它,您将收到一个运行时错误,表明存在未捕获的异常。

Exception propagate upwards in the call-stack.

If you start a new thread from a certain method, it will propagate upwards until it gets to that method.

If that method doesn't catch it, you'll get a runtime error that there's an uncaught exception.

寻找一个思念的角度 2024-11-06 14:20:02

这是捕获并安全处理它的一种方法:

BackgroundWorker bg = new BackgroundWorker();
object o;
bg.DoWork += (c1,c2) =>
{         
        Thread.Sleep(2000);        
        throw new IndexOutOfRangeException();
};

bg.RunWorkerCompleted += (c3,c4) => 
{

 if (((RunWorkerCompletedEventArgs)e).Error != null)
    {
        MessageBox.Show(((RunWorkerCompletedEventArgs)e).Error.Message);
    }
};

Here is one way of catching it and handling it in a safe way:

BackgroundWorker bg = new BackgroundWorker();
object o;
bg.DoWork += (c1,c2) =>
{         
        Thread.Sleep(2000);        
        throw new IndexOutOfRangeException();
};

bg.RunWorkerCompleted += (c3,c4) => 
{

 if (((RunWorkerCompletedEventArgs)e).Error != null)
    {
        MessageBox.Show(((RunWorkerCompletedEventArgs)e).Error.Message);
    }
};
独孤求败 2024-11-06 14:20:02

简而言之,不,它没有。您有几个明显的选择: #

  1. 在新线程启动的方法(创建的线程的堆栈顶部)中将其注销。
  2. 使用像异步委托这样的构造,当您调用 end invoke 时,它​​将返回异常,然后您可以以正常方式捕获它。

In short, no it doesn't. You have a couple of obvious options:#

  1. log it out in the method your new thread starts (top of the stack for the created thread) in.
  2. Use a construct like Asynchronous delegate, which will will return an exception when you call end invoke, which you can then catch in the normal way.
岁月染过的梦 2024-11-06 14:20:02

异常只能在发出的线程上捕获。因此,在另一个线程上抛出异常不会导致另一个线程捕获它。

没有“父”线程的概念。

An exception can only be caught on the thread from which is came. So throwing an exception on another thread won't cause another thread to catch it.

There is no concept of a "parent" thread.

友欢 2024-11-06 14:20:02

对于主线程等待另一个线程完成的特殊情况,有一个非常简单的解决方案(请参阅 https://msdn.microsoft.com/en-us/library/58195swd(v=vs.110).aspx#Examples)。它只需要一个类异常变量。

由异常处理程序完成的修改后的代码示例可能如下所示。

using System;
using System.Threading;

class WaitOne
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);
    static Exception SavedException = null;

    static void Main()
    {
        Console.WriteLine("Main starting.");

        ThreadPool.QueueUserWorkItem(
            new WaitCallback(WorkMethod), autoEvent);

        // Wait for work method to signal.
        autoEvent.WaitOne();
        if (SavedException != null)
        {
           // handle this exception as you want
        }

        Console.WriteLine("Work method signaled.\nMain ending.");
    }

    static void WorkMethod(object stateInfo) 
    {
        Console.WriteLine("Work starting.");

        // Simulate time spent working.
        try
        {
          Thread.Sleep(new Random().Next(100, 2000));
          throw new Exception("Test exception");
        }
        catch (Exception ex)
        {
            SavedException = ex;
        }            

        // Signal that work is finished.
        Console.WriteLine("Work ending.");
        ((AutoResetEvent)stateInfo).Set();
    }
}

There is a very simple solution for the special case when the main thread waits for the completion of the other thread (see https://msdn.microsoft.com/en-us/library/58195swd(v=vs.110).aspx#Examples). It requires only a class exception variable.

The modified code sample completed by an exception handler may look like this.

using System;
using System.Threading;

class WaitOne
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);
    static Exception SavedException = null;

    static void Main()
    {
        Console.WriteLine("Main starting.");

        ThreadPool.QueueUserWorkItem(
            new WaitCallback(WorkMethod), autoEvent);

        // Wait for work method to signal.
        autoEvent.WaitOne();
        if (SavedException != null)
        {
           // handle this exception as you want
        }

        Console.WriteLine("Work method signaled.\nMain ending.");
    }

    static void WorkMethod(object stateInfo) 
    {
        Console.WriteLine("Work starting.");

        // Simulate time spent working.
        try
        {
          Thread.Sleep(new Random().Next(100, 2000));
          throw new Exception("Test exception");
        }
        catch (Exception ex)
        {
            SavedException = ex;
        }            

        // Signal that work is finished.
        Console.WriteLine("Work ending.");
        ((AutoResetEvent)stateInfo).Set();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文