【问题标题】:Why app doesn't crash when exception is thrown [duplicate]为什么抛出异常时应用程序不会崩溃[重复]
【发布时间】:2018-06-26 11:06:25
【问题描述】:

在 WPF 应用程序中,我添加了两个按钮,一个用于启动任务,另一个用于强制 GC 运行:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Task.Run(() =>
        {
            throw new Exception("Some Exception");
        });
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

任务只是抛出一个异常。

在发布配置中运行应用程序时,我按第一个按钮,然后按第二个按钮,我希望应用程序崩溃。无论我按多少次按钮,都不会发生这种情况。

我知道 .NET 4.5 中未观察到的任务吞噬异常的行为:https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/

但是我很困惑为什么一旦 GC 运行,应用程序就不会崩溃。据我了解,一旦收集到任务,就应该抛出错误。

另请注意,我知道这个问题没有回答我的问题 Why doesn't my process terminate when Task has unhandled exception?

标记为答案的评论建议使用ContinueWith,但这也不起作用,应用程序不会崩溃,异常被吞没:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Task.Run(() =>
        {
            throw new Exception("Some Exception");
        }).ContinueWith(t =>
        {
            if (t.IsFaulted) { throw t.Exception.InnerException; }
        });
    }

我已经知道等待 Task 会导致应用崩溃。

【问题讨论】:

  • 你的框架是什么,你设置了 ThrowUnobservedTaskExceptions 吗?
  • 您没有在任何地方使用async/await。您正在触发一个任务并且从不检查它是成功还是失败。如果你这样做了,即如果你写了await Task.Run(()=>throw new Exception(..));,那么这个异常将在await之后被重新抛出
  • 如果您将<ThrowUnobservedTaskExceptions> 元素添加到您的配置文件并按第一个按钮,然后按第二个按钮,该过程应该会崩溃。这是预期的行为。看我的回答。
  • 顺便说一句,应用程序不会崩溃,因为它不应该崩溃。未观察到的任务异常不会使应用程序崩溃
  • 首先,不要更改默认行为,否则您可能会破坏依赖它的库。其次,查看TaskScheduler.UnobservedTaskException 事件的文档。它解释了the process does not terminate by default在发生非观察者任务异常时。

标签: c# multithreading async-await task-parallel-library


【解决方案1】:

但是我很困惑为什么一旦 GC 运行,应用程序就不会崩溃。根据我的理解,一旦收集到任务,就应该抛出 eception。

如果您通过将以下元素添加到您的App.config 来使用旧行为(.NET Framework 4.5 之前),那么您的理解是正确的:

<runtime>
    <ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>

如果您不这样做,UnobservedTaskException 将不会导致进程崩溃。但是仍然会引发异常,因此您可以在这两种情况下处理 TaskScheduler.UnobservedTaskException 事件。

【讨论】:

  • 好的,那么如何在不设置ThrowUnobservedTaskExceptions enabled="true"的情况下处理TaskScheduler.UnobservedTaskException?
  • 就像您处理任何其他事件一样,即将事件处理程序连接到它:TaskScheduler.UnobservedTaskException += (ss, ee) =&gt; { /* do something */ };
  • 谢谢!!!!!!!!!!
【解决方案2】:

这是因为你开枪就忘记了。异常将发生在单独的线程中。如果你想让它崩溃,你必须await它或让它同步。

private void Button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() =>
    {
        throw new Exception("Some Exception");
    });
}

【讨论】:

  • 我知道异常发生在另一个线程上。为什么应用程序不会崩溃?如果您使用new Thread() 创建线程并在线程的方法上抛出异常,应用程序将崩溃。那么为什么在使用 Task.Run 时它也不会崩溃呢?
  • 请注意,我提到我也知道“未观察到的任务”。我知道如果我打电话给await 它会起作用。这不是我要问的。
  • 异常发生在另一个 Task 上,而不是在裸线程上。任务捕获异常,线程杀死 AppDomain
  • @bommelding 你读过我的问题吗?我已经意识到这一点。
  • @DonBox 实际问题是什么?未观察到的异常不应该使应用程序崩溃。解决方案是添加适当的异常处理并实际观察任务。处理UnobservedTaskException 事件只是作为最后的手段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-18
相关资源
最近更新 更多