取消任务

时间:2012-12-15 21:14:01

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

我试图在取消下面的任务

上运行一个简单的例子
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);

我预计Console.WriteLine("Task 2 cancelled? {0}", task2.IsCanceled);会打印**"Task 2 cancelled? True"**,但会打印“False”

你知道发生了什么事吗?这是预期的行为吗?感谢。

编辑:确保在调用取消请求之前未完成任务。我添加了Console.ReadLine()

3 个答案:

答案 0 :(得分:5)

首先,也许您误解了IsCanceled的含义?这并不意味着“此Task正在等待取消,因此它应该很快完成”,这意味着“此Task已取消,现在已完成”。

如果你没有误解,请考虑事件的顺序是什么。会发生什么:

  1. ThrowIfCancellationRequested()被调用,但令牌尚未取消,所以它不会抛出。
  2. 调用
  3. Thread.Sleep(),因此运行Task的线程会休眠。
  4. Cancel()被召唤。
  5. IsCanceled已经过检查。 Task中的代码没有机会意识到令牌已被取消,因此它仍在运行,因此IsCanceled会返回false
  6. 再次调用
  7. ThrowIfCancellationRequested(),此时它会抛出,实际上会取消Task
  8. 这就是ISCanceled向您返回false的原因。如果您希望它返回true,则可以在检查Thread.Sleep(150)之前添加IsCanceled之类的内容,或者更好的是,等待Task完成。

答案 1 :(得分:2)

任务在您致电取消之前结束,请看下面的内容,这可能有助于更多地了解如何解决您的问题

通过阅读http://social.msdn.microsoft.com/Forums/da-DK/parallelextensions/thread/9f88132a-f8bd-4885-ab63-645d7b6c2127,似乎该令牌用于在“真正”启动任务之前取消任务,但是在排队之后。

  

这是一种取消计划发生但尚未开始的任务的方法。一旦任务运行,取消它的唯一方法是通过您自己在方法中的检查合作。如果没有这个,你必须始终启动任务,然后在内部进行检查,这将增加许多额外的,不必要的开销

您甚至可以从Cancellation token in Task constructor: why?

阅读

答案 2 :(得分:2)

这不是答案,但在评论中写的时间太长

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);
  • 上面的代码打印出预期的内容,我从来没有打印过'Task 2 - Int value {0}'所以我认为它在取消之前没有完成。
  • 请注意,取消任务会在我的示例中引发异常
  • 有一些patterns for handling exceptions using tasks可以很好地阅读。