【问题标题】:Task.Run and CancellationToken. How does cancellation work in this scenario? [duplicate]Task.Run 和 CancellationToken。在这种情况下取​​消是如何工作的? [复制]
【发布时间】:2021-03-09 23:29:04
【问题描述】:

为什么我们在接下来的 2 个场景中有 2 个不同的结果?在这些样本中 token.IsCancellationRequested = true。如果我评论 if(token.IsCancellationRequested),为什么功能会发生变化,而实际上我们可以输入 if(true) 而不是它。

我在某处读到,为了获得 TaskCanceledException ( Status = Canceled ),我们需要遵循以下 3 个条件:

  1. 抛出 OperationCanceledException 并将令牌传递给它的构造函数
  2. 将相同的令牌传递给创建任务 (Task.Run) 的方法
  3. IsCancellationRequested 应该为真。

确实如此,如果我们使用 if(token.IsCancellationRequested) throw new OperationCanceledException(token) (equals to token.ThrowIfCancellationRequested) (第二种情况),我们需要遵循其他 2 个条件,但在第一种情况下,如果我们评论 if (token.IsCancellationRequested)(我们甚至可以从 CTS 构造函数中删除 1)我们仍然会得到 Canceled 状态。

1.此处状态已取消

CancellationTokenSource cts = new CancellationTokenSource(1);
        var token = cts.Token;
        var task = Task.Run(() =>
        {
                Thread.Sleep(5);
                // if(token.IsCancellationRequested)
                throw new OperationCanceledException(token);
        });

        Thread.Sleep(50);
        Console.WriteLine(task.Status);

2.这里 - 故障。

CancellationTokenSource cts = new CancellationTokenSource(1);
        var token = cts.Token;
        var task = Task.Run(() =>
        {
            Thread.Sleep(5); 
            if(token.IsCancellationRequested) // true
                throw new OperationCanceledException(token);
        });

        Thread.Sleep(50);
        Console.WriteLine(task.Status);

【问题讨论】:

  • 顺便说一句 - 你应该打电话给ThrowIfCancellationRequested,而不是测试/扔自己
  • if(token.IsCancellationRequested) throw new OperationCanceledException(token) 等于 ThrowIfCancellationRequested,但在某处我读到,为了拥有 TaskCanceledException (Status = Canceled),我们需要: 1. 抛出 OperationCanceledException 并通过将令牌传递给它的构造函数 2. 将相同的令牌传递给创建任务 (Task.Run) 的方法 3. IsCancellationRequested 应该为 true
  • 我认为TaskCanceledException 只是捕获OperationCanceledException 的结果。但这样做的规范方法是使用ThrowIfCancellationRequested(),这取决于IsCancellationRequested
  • 您的两个示例调用了Task.Run() 的不同重载,这反过来又具有不同的取消行为。查看副本。

标签: c# .net task-parallel-library


【解决方案1】:

似乎如果编译器可以在编译时知道任务将始终抛出OperationCanceledException,则将以Canceled状态结束,否则它将以Faulted结束。

void Main()
{
    CancellationTokenSource cts = new CancellationTokenSource(1);
    cts.Cancel();
    var token = cts.Token;
    var task = Task.Run(() =>
    {
        //if(GetTrue())  //Faulted
        if(true)         //Canceled
            throw new OperationCanceledException();
    });
    
    Thread.Sleep(50);
    Console.WriteLine(task.Status);
}

bool GetTrue()
{
    return true;
}

但是,如果您将相同的令牌发送到Task.Run,就像您在任务中抛出一样,它将以Canceled结束。

void Main()
{
    CancellationTokenSource cts = new CancellationTokenSource(10000);
    var token = cts.Token;
    var task = Task.Run(() =>
    {
        cts.Cancel();
        token.ThrowIfCancellationRequested();
    }, token);
    
    Thread.Sleep(50);
    Console.WriteLine(task.Status);
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
  • 2016-12-05
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 2023-03-24
相关资源
最近更新 更多