6

我尝试运行一个简单的示例来取消如下所示的任务

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().

4

3 回答 3

5

首先,也许你误解了什么IsCanceled意思?这并不意味着“这Task是等待取消,所以它应该很快完成”,它的意思是“这Task已经被取消了,现在已经完成了”。

如果您没有误解这一点,请考虑一下事件的确切顺序。会发生什么:

  1. ThrowIfCancellationRequested()被调用,但令牌还没有被取消,所以它不会抛出。
  2. Thread.Sleep()被调用,所以运行Task睡眠的线程。
  3. Cancel()叫做。
  4. IsCanceled被检查。中的代码Task没有机会意识到令牌已被取消,因此它仍在运行,因此IsCanceled返回false
  5. ThrowIfCancellationRequested()再次调用,这次它抛出,实际上取消了Task.

这就是为什么ISCanceled回到false你身边。如果你想让它返回,你可以在检查之前true添加类似的东西,或者更好的是,实际上等待完成。Thread.Sleep(150)IsCanceledTask

于 2012-12-15T22:34:13.807 回答
2

任务在您要求取消之前已结束,请查看以下内容,这可能有助于进一步了解如何解决您的问题

通过从这里阅读http://social.msdn.microsoft.com/Forums/da-DK/parallelextensions/thread/9f88132a-f8bd-4885-ab63-645d7b6c2127似乎令牌用于在任务之前取消任务“真的”开始了,但在排队之后。

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

您甚至可以从Task 构造函数中的 Cancellation 标记中读取它:为什么?

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