2

私は非常に奇妙な問題を抱えています.これが私のコードです:

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」が作成されないこともあれば、何もないファイルが作成されることもある……?

ここに画像の説明を入力

【解決済み——提案によると、これが答えです】</p>

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

1 に答える 1

0

OperationCanceledException特定のトークンに対して がスローされ、これがタスクの作成時に渡したトークンと同じである場合、これは通常の予想されるキャンセル フローであるため、未処理\未観察の例外として扱われません。この例外は、代わりにタスクの状態を Cancelled に設定するだけです。あなたの場合もそうです:

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 ハンドラーによってインターセプトされます。

問題は、この例外を監視されていないものとして扱いたいのはなぜですか? タスクをキャンセルできると思っていたのにキャンセルすると、現在はキャンセル状態になっています。監視されていない\処理されていないものはありません。

于 2016-11-26T15:16:49.130 に答える