【问题标题】:Any way to catch an exception occurring on a thread I don't own?有什么方法可以捕获我不拥有的线程上发生的异常?
【发布时间】:2015-06-15 15:17:17
【问题描述】:

我正在使用一个糟糕的第三方库,因为不幸的是我别无选择。当我调用这个库时,它会在内部创建一堆线程,并且偶尔会在其中一个线程上抛出 NullReferenceException。即使我不拥有引发它们的线程,我有什么方法可以捕获这些异常吗?我无法更改第三方代码。

作为一个简单的例子来说明问题:

public static void main()
{
    try
    {
        var crappyLib = new CrappyLibrary();
        crappyLib.DoCrappyThings();
    }
    catch
    {
        Console.WriteLine("This never happens");
    }
}

// I do not own the following code, I can't change it
public class CrappyLibrary
{
    public void DoCrappyThings()
    {
        var t = new Thread(DoWork);
        t.Start();
    }
    private void DoWork()
    {
        throw new ThisLibrarySucksException();
    }
}

【问题讨论】:

  • 你能在你使用的第三方代码周围使用try...catch吗?
  • 可以,但是异常不会传播到调用线程。
  • 通常,在 .NET Web 应用程序中,您在 global.asax -> void Application_Error(object sender, EventArgs e) 中有一个事件 - 您可以在其中捕获应用程序中发生的所有错误。你在做什么类型的应用程序?
  • 建议的线程没有回答问题,我有兴趣捕获我不拥有的线程的异常,因此我无法尝试捕获异常,它在我无权访问的堆栈上执行.
  • 这不是一个骗局,因为 OP 无法更改用于启动线程的代码

标签: c# multithreading exception


【解决方案1】:

在所描述的情况下,我最担心的是第三方库中的异常线程终止。一旦线程抛出,您就无法通过正确的方式捕获异常,因为您不是该线程调用的所有者(而且它不知道应该将异常传播给您;不像它比方说,发生在 TPL 中)。因此,即使通过全局处理程序处理此类异常,这也可能是不正确的方式,因为在任何此类异常之后,lib 可能会以不一致的状态出现。

所以这里的安全方式是将库隔离在某个范围内,并在出现任何异常后重新启动该范围。比方说,将库加载到单独的域中。

【讨论】:

  • 我试图避免在另一个进程中对此进行沙箱处理,但看起来它可能是唯一的解决方案。我对这个库没有任何控制权,但我必须使用它,因为我无法进入,而且我无法获得对这个问题的支持。我正在寻找解决糟糕情况的方法。
  • @ConditionRacer,小修正:C# 域不是其他进程,它们是嵌入到 .NET 基础架构中的隔离级别,因此您无需担心跨应用程序的事情。所以特定的应用程序可以有多个域,因为大多数应用程序只是随意使用默认域。附言作为多年的外包商,我感受到你的痛苦并理解这种情况
【解决方案2】:

如果您的目标是防止由于这些不受您控制的未处理异常而提前终止您的进程,那么您可以将 legacyUnhandledExceptionPolicy 设置添加到您的 app.config 中,以防止未处理的线程异常终止整个过程。

显然,解决方案并不完美,因为未处理的异常可能会破坏线程的状态。但至少这是一个你可以考虑的选择。

请查看有关此here 的文档,以更好地了解启用此设置的含义。

您的app.config 必须如下所示:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

编辑: 只是一个想法,但也许上述设置与为AppDomain.UnhandledException 添加事件处理程序相结合可以帮助您满足您的需求。

使用AppDomain.UnhandledException,您可以检测到故障,以便您知道何时需要触发重试,或者在这些情况下您需要执行的任何其他操作。

legacyUnhandledExceptionPolicy 设置仍可用于防止进程关闭,从而让您有机会执行重试。

【讨论】:

    【解决方案3】:

    希望对你有帮助https://msdn.microsoft.com/en-GB/library/system.windows.forms.application.threadexception.aspx

    您可以尝试类似的方法(来自文章)

    Application.ThreadException += new ThreadExceptionEventHandler  (ErrorHandlerForm.Form1_UIThreadException);
    
    // Set the unhandled exception mode to force all Windows Forms errors to go through 
    // our handler.
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
    
    // Add the event handler for handling non-UI thread exceptions to the event. 
    AppDomain.CurrentDomain.UnhandledException +=
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    

    【讨论】:

    • 前两个示例仅适用于 Windows 窗体应用程序...第三个示例可让您查看错误,但不会阻止应用程序关闭。
    • 不幸的是,我想做的不仅仅是记录异常。我正在努力恢复并继续。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    • 2015-03-08
    • 1970-01-01
    • 2010-11-16
    • 2012-01-22
    相关资源
    最近更新 更多