Task任务取消
取消任务使用CancellationToken这个令牌,这是个struct结构体。
看一段代码:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
// Define the cancellation token.
CancellationTokenSource source1 = new CancellationTokenSource();
CancellationToken token = source1.Token;
CancellationTokenSource source2 = new CancellationTokenSource();
CancellationToken token2 = source2.Token;
TaskFactory factory = new TaskFactory(token);
Task tsk1 = factory.StartNew(() =>
{
System.Console.WriteLine("This is a new task.");
Thread.Sleep(5000);
if(token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
});
Thread.Sleep(1000);
source1.Cancel();
try
{
tsk1.Wait();
}
catch (AggregateException ae)
{
foreach (Exception e in ae.InnerExceptions)
{
if (e is TaskCanceledException)
Console.WriteLine("Exception 1 : {0}",
((TaskCanceledException)e).Message);
else
Console.WriteLine("Exception 2 : " + e.GetType().Name);
}
}
finally
{
source1.Dispose();
}
}
}
代码运行结果:
This is a new task.
Exception 1 : A task was canceled.
新的任务在1秒后(28行)通过调用source1对象的Cancel()启动取消任务操作,但是实际上由于新的任务在5秒后才能检测到,所以,异常取消任务的异常信息也是在5秒后触发的。这就是说启动取消和实际取消任务操作需要配合使用,一个地方Cancel(),另一个地方需要去检测相应的令牌,并且最重要的是要调用ThrowIfCancellationRequested()方法抛出异常,这个抛出异常动作才是真正导致任务被取消。(因此,实际上我们完全可以抛出其他任何异常或者直接任务返回也可以实现任务取消操作,只不过这都是我们自己的用户代码。微软只不过给我们提供了一套解决方案,这套解决方案就是使用CancellationTokenSource ,CancellationToken 这些类,并且可以和Task的Status属性配合改变任务状态值)。
此外,TaskFactory类的对象在构造函数中传入了token令牌(17行),这个令牌对象与23行抛出异常的令牌是同一个令牌,因此捕获的是TaskCanceledException,此时Task任务的Status状态值是Canceled。我们也可以在17行的TaskFactory类构造函数中使用默认构造函数,不携带token令牌对象,此时,我们还可以在StartNew()方法的第二个参数中携带上token令牌,只要这个令牌和任务中实际使用的令牌是同一个令牌,都能成功取消任务,并且任务状态修改位Canceled。如果令牌不一致(比如17行token改为token2),那么任务仍然能够被取消(毕竟任务由于抛出异常而真正被终止了),只不过此时抛出的异常是OperationCanceledException。
还有一点,如果将28行的source1.Cancel()移动到18行之前(即StartNew()方法之前),这时新建的任务根本就不会执行,因为已经被提前取消了,此时的前提条件是TaskFactory构造函数或者StartNew()方法需要传入token令牌,否则任务不会被取消。因此,TaskFactory()构造函数或者StartNew()方法传入token令牌的另一个功能就是可以提前取消新建的任务,这个时候取消任务速度也足够快,因为快到任务的第一句话都不会执行。
另外一篇非常重要的微软参考文献:
Task Cancellation