如何在 Task 引发异常而不等待终结器的情况下使应用程序崩溃

本文关键字:情况下 崩溃 应用程序 等待 Task 异常 | 更新日期: 2023-09-27 18:36:47

我们在.Net 4(没有可用的异步等待)应用程序中使用任务,有时它们用于启动"即发即弃"操作,如下所示:

private void Test()
{
    Task task = Task.Factory.StartNew(() =>
    {
        throw new ApplicationException("Test");
    });
}
我们希望此异常在不等待任务的情况下使应用程序

崩溃(否则将其放在任务中是没有意义的,至少在我们的场景中是这样),并且无需等待终结器,因为我们希望在发生意外错误时关闭应用程序以避免状态损坏(我们正在保存异常发生时存在的状态)。

我的猜测是,我们应该以某种方式使用延续任务,但这会将延续代码放在另一个不会使应用程序崩溃的任务中,所以我在这里被阻止了。

任何帮助将不胜感激

编辑:如果切换到线程池,结果是预期的。以下代码使应用程序崩溃:

ThreadPool.QueueUserWorkItem((c) =>
{
    throw new ApplicationException("Test");
});

如何在 Task 引发异常而不等待终结器的情况下使应用程序崩溃

我终于找到了如何做到这一点,即使它有点复杂:

namespace ThreadExceptions
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    public static class TaskExtensions
    {
        public static Task ObserveExceptions(this Task task)
        {
            return task.ContinueWith((t) =>
            {
                ThreadPool.QueueUserWorkItem((w) =>
                {
                    if (t.Exception != null)
                    {
                        foreach (Exception ex in t.Exception.InnerExceptions)
                        {
                            throw new TaskException(ex);
                        }
                    }
                });
            }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.PreferFairness);
        }
    }
}

这将使应用程序崩溃而无需等待任务。这就是我一直在寻找的。

使用 FailFast 尝试此解决方案

此方法在不运行任何活动的情况下终止进程 尝试/最终块或终结器

private void Test()
{
    Task task = Task.Factory.StartNew(() =>
    {
        Environment.FailFast("Test", new ApplicationException("Test"));
    });
}

您可以编写自己的Task类来包装要使用的各种Task方法,并向其添加异常处理。

例如:

public static class TaskWithExceptionHandling
{
    public static Task StartNew(Action action)
    {
        var task = Task.Factory.StartNew(action);
        task.ContinueWith(exceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
        return task;
    }
    private static void exceptionHandler(Task task)
    {
        // Handle unhandled aggregate task exception from 'task.Exception' here.
        Console.WriteLine("Exception: " + task.Exception.GetBaseException().Message);
    }
}

您将像这样替换Task类:

Task task = TaskWithExceptionHandling.StartNew(() =>
{
    throw new InvalidOperationException("Test exception");
});
Console.ReadLine();