【问题标题】:Can "ThrowIfCancellationRequested" not be caught by TaskScheduler_UnobservedTaskException?TaskScheduler_UnobservedTaskException 不能捕获“ThrowIfCancellationRequested”吗?
【发布时间】:2016-11-26 09:58:50
【问题描述】:

我有一个非常奇怪的问题,现在这是我的代码:

namespace TaskParallelTest
{
    using System.Threading;
    using System.Threading.Tasks;
    using System;
    using System.IO;

    public class Program
    {
        static Program()
        {
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
        }
        private static void DoPrint(int id, CancellationToken cToken)
        {
            Thread.Sleep(100);
            if (!cToken.IsCancellationRequested)
            {
                Console.WriteLine("Id is:" + id + ";Current State:" + cToken.IsCancellationRequested);
                cToken.Register(() => Console.WriteLine("Rollback for:" + id));
            }
        }
        static void Main(string[] args)
        {
            CancellationTokenSource cTokenSource = new CancellationTokenSource();

            Task.Run(() =>
            {
                for (int i = 1; i < 6; i++)
                {
                    cTokenSource.Token.ThrowIfCancellationRequested();
                    DoPrint(i, cTokenSource.Token);
                }
            }, cTokenSource.Token);

            Random r = new Random();

            Thread.Sleep(400);
            cTokenSource.Cancel(true);
            Thread.Sleep(10000);
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Console.WriteLine("OK");
            Console.ReadLine();
        }

        private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            File.WriteAllText("C:\\Resume\\Error.txt", e.Exception.StackTrace);
            e.SetObserved();
        }
    }
}

让我感到气愤的是为什么“UnobservedTaskException”事件无法被捕获?我使用了 GC.Collect() 和 Thread.Sleep(),但没有任何帮助……?

有时,“Error.txt”没有创建,有时,创建的文件没有任何内容......?

【已解决——现在根据建议,给你答案】

1) 请注意,我应该删除“取消”并在此处模拟异常:

static void Main(string[] args)
        {
            CancellationTokenSource cTokenSource = new CancellationTokenSource();

            Task.Run(() =>
            {
                for (int i = 1; i < 6; i++)
                {
                    if (i==5)
                    {
                        throw new Exception("Error occured!");
                    }
                    DoPrint(i, cTokenSource.Token);
                }
            },cTokenSource.Token)
            .ContinueWith
            (
                t =>
                {
                    Console.WriteLine("Error has happened now.");
                    Console.WriteLine(t.IsFaulted);
                },
                TaskContinuationOptions.OnlyOnFaulted
            );

            Thread.Sleep(400);
            //cTokenSource.Cancel();
            //Thread.Sleep(2000);
            GC.Collect();
            GC.WaitForPendingFinalizers();
            //Thread.Sleep(6000);
            Console.WriteLine("OK");
            Console.ReadLine();
        }

2)然后展平异常(因为那是一个聚合异常):

 private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            foreach (var item in e.Exception.Flatten().InnerExceptions)
            {
                Console.WriteLine(item.StackTrace);
            }
            e.SetObserved();
        }

【问题讨论】:

    标签: c# unobserved-exception


    【解决方案1】:

    如果 OperationCanceledException 被抛出特定令牌,并且这与您在创建任务时传递的令牌相同 - 它不会被视为未处理\未观察到的异常,因为它只是正常的预期取消流程。此异常只会将任务状态设置为已取消。你的情况也是如此:

    var task = Task.Run(() =>
    {
       for (int i = 1; i < 6; i++)
       {
           // this exception is associated with cTokenSource.Token
           cTokenSource.Token.ThrowIfCancellationRequested();
           DoPrint(i, cTokenSource.Token);
       }
    }, cTokenSource.Token); // and this is the same token you pass when creating a task
    

    如果不是这样(例如,您在创建任务时传递了不同的令牌)- UnobservedTaskException 处理程序将拦截异常。

    问题是:为什么您希望将此异常视为未观察到的?您希望可以取消任务,然后取消它,它现在处于已取消状态。没有任何未观察到\未处理。

    【讨论】:

    • 是的:看来我可以通过ContinueWith来捕捉Canceled状态……而我无法通过事件捕捉到代码。我曾经认为任何异常都可以被 UnobservedException 捕获,因为“取消也是异常”。但仍然要说谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 2011-07-15
    相关资源
    最近更新 更多