当任务抛出异常而不等待终结器时如何使应用程序崩溃

How to make an application crash when a Task throws an exception without waiting the finalizer

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

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

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

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

任何帮助将不胜感激

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

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

使用 FailFast

尝试此解决方案

This method terminates the process without running any active try/finally blocks or finalizers.

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

您可以编写自己的 Task class 来包装您要使用的各种 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 class:

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

Console.ReadLine();

我终于找到了方法,虽然有点复杂:

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);
        }
    }
}

这会使应用程序在没有等待任务的情况下崩溃。这就是我要找的。