简体   繁体   English

取消任务

[英]Cancellation of a task

I tried to run a simple example on the cancellation of a task like the one below 我尝试在取消下面的任务时运行一个简单的例子

CancellationTokenSource tokenSource2 = new CancellationTokenSource();

CancellationToken token2 = tokenSource2.Token;


Task task2 = new Task(() =>
{
    for (int i = 0; i < int.MaxValue; i++)
    {
        token2.ThrowIfCancellationRequested();
        Thread.Sleep(100);
        Console.WriteLine("Task 2 - Int value {0}", i);
    }
}, token2);

task2.Start();

Console.WriteLine("Press any key to cancel the task");
Console.ReadLine();

tokenSource2.Cancel();
Console.WriteLine("Task 2 cancelled? {0}", task2.IsCanceled);

I expected that Console.WriteLine("Task 2 cancelled? {0}", task2.IsCanceled); 我期望Console.WriteLine("Task 2 cancelled? {0}", task2.IsCanceled); would print **"Task 2 cancelled? True"** , but it printed "False" . 将打印**"Task 2 cancelled? True"** ,但它打印“假”

Do you know what happened? 你知道发生了什么吗? Is that the expected behaviour? 这是预期的行为吗? Thanks. 谢谢。

EDIT: to ensure that the task hasn't completed before the cancellation request is called. 编辑:确保在调用取消请求之前未完成任务。 I added the Console.ReadLine() . 我添加了Console.ReadLine()

First, maybe you misunderstand what IsCanceled means? 首先,也许你误解了IsCanceled意思? It doesn't mean “this Task is pending cancellation, so it should complete shortly”, it means “this Task has been canceled, it is now complete”. 这并不意味着“此Task正在等待取消,因此它应该很快完成”,这意味着“此Task已被取消,现在已完成”。

If you didn't misunderstand that, think about what exactly the sequence of events is. 如果你没有误解,请考虑事件的顺序是什么。 What happens is this: 这是怎么回事:

  1. ThrowIfCancellationRequested() is called, but the token wasn't canceled yet, so it doesn't throw. ThrowIfCancellationRequested() ,但令牌尚未取消,因此它不会抛出。
  2. Thread.Sleep() is called, so the thread running the Task sleeps. 调用Thread.Sleep() ,因此运行Task的线程会休眠。
  3. Cancel() is called. 调用Cancel()
  4. IsCanceled is checked. IsCanceled被检查。 The code in the Task didn't have a chance to realize that the token was canceled, so it's still running, so IsCanceled returns false . Task的代码没有机会意识到令牌已被取消,因此它仍在运行,因此IsCanceled返回false
  5. ThrowIfCancellationRequested() is called again, this time it throws, which actually cancels the Task . 再次调用ThrowIfCancellationRequested() ,这次抛出,实际上取消了Task

This is why ISCanceled is returning false to you. 这就是为什么ISCanceled会向您返回false If you want it to return true , you could add something like Thread.Sleep(150) before checking IsCanceled , or, even better, actually wait for the Task to complete. 如果你想让它返回true ,你可以在检查IsCanceled之前添加类似Thread.Sleep(150)东西,或者更好的是,实际上等待Task完成。

The Task ended before you call for cancellation, take a look at the following below this may help to shed some more light on how to resolve your issue 任务在您要求取消之前结束,请看下面的内容,这可能有助于更多地了解如何解决您的问题

By reading from here http://social.msdn.microsoft.com/Forums/da-DK/parallelextensions/thread/9f88132a-f8bd-4885-ab63-645d7b6c2127 it seems that the token is used to cancel the task BEFORE the task is "really" started, but after it has been queued. 通过这里阅读http://social.msdn.microsoft.com/Forums/da-DK/parallelextensions/thread/9f88132a-f8bd-4885-ab63-645d7b6c2127 ,似乎令牌用于在任务之前取消任务“真的”开始了,但在排队之后。

It's more a way to cancel a task that's scheduled to occur, but not started yet. 这是一种取消计划发生但尚未开始的任务的方法。 Once the task is running, the only way to cancel it is cooperatively via your own checking within the method. 一旦任务运行,取消它的唯一方法是通过您自己在方法中的检查合作。 Without this, you'd have to always start the task, then check it internally, which would add a lot of extra, unnecessary overhead 如果没有这个,你必须始终启动任务,然后在内部进行检查,这会增加许多额外的,不必要的开销

You can even read it from Cancellation token in Task constructor: why? 您甚至可以在Task构造函数中的Cancellation token中读取它:为什么?

This is not an answer but too long to write in a comment 这不是一个答案,但在评论中写的时间太长了

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;

Task task = new Task(() =>
{
    for (int i = 0; i < int.MaxValue; i++)
    {
        cancellationToken.ThrowIfCancellationRequested();
        Console.WriteLine("Task 2 - Int value {0}", i);
    }
}, cancellationToken);

task.Start();

cancellationTokenSource.Cancel();
try
{
    task.Wait();
}
catch (AggregateException ae)
{
    if(ae.InnerExceptions.Single() is TaskCanceledException)
        Console.WriteLine("Caught TaskCanceledException");
    else
        Console.WriteLine("Did not catch canceled");
}
Console.WriteLine("Task 2 cancelled? {0}", task.IsCanceled);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM