CancellationTokenSource不到预期效果效果、CancellationTokenSource

2023-09-03 02:43:48 作者:赴人间惊鸿宴

什么是预期在这种情况下,是,如果用户取消通过点击输入任务,其他任务由 ContinueWith 钩将运行,但它不是这样的,因为每一个 AggregateException 尽管明确的处理在不断抛出 ContinueWith 这显然是没有被执行。 在下面的任何澄清吗?

 类节目
{
    静态无效的主要(字串[] args)
    {
        CancellationTokenSource tokensource =新CancellationTokenSource();
        的CancellationToken令牌= tokensource.Token;

        任务task = Task.Run(()=>
        {
            而(!token.IsCancellationRequested)
            {
                Console.Write(*);
                Thread.sleep代码(1000);
            }
        },令牌).ContinueWith((T)=>
        {
            t.Exception.Handle((E)=>真正的);
            Console.WriteLine(您已取消任务);
        },TaskContinuationOptions.OnlyOnCanceled);

        Console.WriteLine(preSS任意键取消);
        到Console.ReadLine();
        tokensource.Cancel();
        task.Wait();
    }
}
 

解决方案

让我们先从几个事实:

当你通过一个的CancellationToken 作为一个参数 Task.Run ,它只有一个效果,如果它的取消< STRONG>之前任务开始运行。如果任务已经运行,将不可以取消。 要得到一个任务取消的在它已开始运行,你需要使用 CancellationToken.ThrowIfCancellationRequested ,不是的CancellationToken .IsCancellationRequested 。 如果任务被取消,其异常属性不持有任何的异常,是。 如果一个后续任务并不出于某种原因,这意味着它被取消运行。 任务包含本身+及其所有子任务异常(因此, AggregateException )。

所以,这是你的code会发生什么:

任务开始运行,因为令牌没有被取消。它将运行,直到令牌被取消。之后它会结束延续的不会运行,因为它只有在preceding取消任务运行,并且它一直没有。当你等待将抛出任务的 AggregateException TaskCanceledException 因为在继续被取消了(如果你能删除持续异常会消失)。

解决方法:

您需要修复的任务,所以它实际上被取消,并删除(或空检查),异常处理,因为没有什么异常:

  VAR任务= Task.Run(新动作(()=&GT;
{
    而(真)
    {
        token.ThrowIfCancellationRequested();
        Console.Write(*);
        Thread.sleep代码(1000);
    }
}),令牌).ContinueWith(
    T =&GT; Console.WriteLine(您已取消任务),
    TaskContinuationOptions.OnlyOnCanceled);
 
前两月融资稳定,CPI超预期,继续关注价格传导效应 2月金融和物价数据点评

what's expected in this case, is that if the user cancels the task by hitting enter, the other task hooked by ContinueWith will run, but it's not the case, as per an AggregateException keeps thrown despite the explicit handling in the ContinueWith which is apparently not being executed. any clarification on the below please?

class Program
{
    static void Main(string[] args)
    {
        CancellationTokenSource tokensource = new CancellationTokenSource();
        CancellationToken token = tokensource.Token;

        Task task = Task.Run(() =>
        {
            while (!token.IsCancellationRequested)
            {
                Console.Write("*");
                Thread.Sleep(1000);
            }
        }, token).ContinueWith((t) =>
        {
            t.Exception.Handle((e) => true);
            Console.WriteLine("You have canceled the task");
        }, TaskContinuationOptions.OnlyOnCanceled);

        Console.WriteLine("Press any key to cancel");
        Console.ReadLine();
        tokensource.Cancel();
        task.Wait();
    }
}

解决方案

Let's start with a few facts:

When you pass a CancellationToken as a parameter for Task.Run it only has an effect if it's cancelled before the task started running. If the task is already running it will not be canceled. To get a task canceled after it has started running, you need to use CancellationToken.ThrowIfCancellationRequested, not CancellationToken.IsCancellationRequested. If a task is canceled, its Exception property doesn't hold any exceptions and is null. If a continuation task does not run for some reason, that means it was canceled. A task contains exceptions from itself + all its child tasks (hence, AggregateException).

So this is what happens in your code:

The task starts running, because the token is not canceled. It will run until the token gets canceled. After it will end the continuation will not run because it only runs when the preceding task is canceled, and it hasn't been. When you Wait the task it will throw an AggregateException with a TaskCanceledException because the continuation was canceled (if you would remove that continuation the exception will go away).

Solution:

You need to fix the task so it would actually be canceled, and remove (or null check) the exception handling because there is no exception:

var task = Task.Run(new Action(() =>
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        Console.Write("*");
        Thread.Sleep(1000);
    }
}), token).ContinueWith(
    t => Console.WriteLine("You have canceled the task"),
    TaskContinuationOptions.OnlyOnCanceled);