System.Threading.Tasks.Task 和 System.Threading.Tasks.Task<TResult> 类通过使用取消令牌来支持取消。 有关详细信息,请参阅托管线程中的取消。 在 Task 类中,取消涉及用户委托(表示可取消作)和请求取消的代码之间的合作。 成功取消涉及调用 CancellationTokenSource.Cancel 方法的请求代码,以及及时终止操作的用户委托。 可以使用以下选项之一终止操作:
从委托中返回。 在许多情况下,此选项已足够。 但是,这样取消的任务实例会过渡到 TaskStatus.RanToCompletion 状态,而不是 TaskStatus.Canceled 状态。
引发 OperationCanceledException,并将其传递到在其上请求了取消的标记。 执行的首选方法是使用 ThrowIfCancellationRequested 该方法。 这样取消的任务将转换为“已取消”状态,调用代码可以使用该状态来验证该任务是否响应了取消请求。
以下示例显示了引发异常的任务取消的基本模式:
注释
标记将传递到用户委托和任务实例。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Run(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token); // Pass same token to Task.Run.
tokenSource2.Cancel();
// Just continue on this thread, or await with try-catch:
try
{
await task;
}
catch (OperationCanceledException e)
{
Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
}
finally
{
tokenSource2.Dispose();
}
Console.ReadKey();
}
}
Imports System.Threading
Imports System.Threading.Tasks
Module Test
Sub Main()
Dim tokenSource2 As New CancellationTokenSource()
Dim ct As CancellationToken = tokenSource2.Token
Dim t2 = Task.Factory.StartNew(Sub()
' Were we already canceled?
ct.ThrowIfCancellationRequested()
Dim moreToDo As Boolean = True
While moreToDo = True
' Poll on this property if you have to do
' other cleanup before throwing.
If ct.IsCancellationRequested Then
' Clean up here, then...
ct.ThrowIfCancellationRequested()
End If
End While
End Sub _
, tokenSource2.Token) ' Pass same token to StartNew.
' Cancel the task.
tokenSource2.Cancel()
' Just continue on this thread, or Wait/WaitAll with try-catch:
Try
t2.Wait()
Catch e As AggregateException
For Each item In e.InnerExceptions
Console.WriteLine(e.Message & " " & item.Message)
Next
Finally
tokenSource2.Dispose()
End Try
Console.ReadKey()
End Sub
End Module
有关完整示例,请参阅 如何取消任务及其子任务。
当任务实例观察到由用户代码引发的OperationCanceledException时,它会将异常的令牌与其关联的令牌(即传递给创建任务的API的令牌)进行比较。 如果令牌相同,并且令牌 IsCancellationRequested 的属性返回 true
,则任务会将此项解释为确认取消并转换为“已取消”状态。 如果不使用 Wait 或 WaitAll 方法等待任务,则任务只会将其状态设置为 Canceled。
如果在等待的任务转换为“已取消”状态,就会引发 System.Threading.Tasks.TaskCanceledException 异常(包装在 AggregateException 异常中)。 此异常表示成功取消,而不是出错的情况。 因此,任务 Exception 的属性返回 null
。
如果令牌 IsCancellationRequested 的属性返回 false
或异常的令牌与 Task 的令牌不匹配,则 OperationCanceledException 被视为正常异常,导致任务转换为错误状态。 存在其他异常也会导致任务过渡到故障状态。 可以在属性中 Status 获取已完成任务的状态。
在请求取消操作之后,任务可能还会继续处理一些项。