Отмена задач
System.Threading.Tasks.Task<TResult> Классы System.Threading.Tasks.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
или если маркер исключения не соответствует маркеру задачи, OperationCanceledException он обрабатывается как обычное исключение, что приводит к переходу задачи в состояние сбоя. Наличие других исключений также приведет к переходу задачи в состояние сбоя. Состояние завершения задачи можно получить в свойстве Status .
Возможно, задача может продолжать обрабатывать некоторые элементы после запроса отмены.