Отмена задачTask Cancellation

Классы System.Threading.Tasks.Task и System.Threading.Tasks.Task<TResult> поддерживают отмену с помощью токенов отмены в .NET Framework.The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> classes support cancellation through the use of cancellation tokens in the .NET Framework. См. дополнительные сведения об отмене в управляемых потоках.For more information, see Cancellation in Managed Threads. В классах задач отмена включает взаимодействие между пользовательским делегатом, который представляет операцию отмены, и кодом, который запросил отмену.In the Task classes, cancellation involves cooperation between the user delegate, which represents a cancelable operation and the code that requested the cancellation. Успешная отмена включает запрашивающий код, вызывающий метод CancellationTokenSource.Cancel , и пользовательский делегат, своевременно завершающий операцию.A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method, and the user delegate terminating the operation in a timely manner. Операцию можно завершить одним из следующих способов.You can terminate the operation by using one of these options:

  • Путем простого возврата из делегата.By simply returning from the delegate. Во многих сценариях этого достаточно, однако экземпляр задачи, отмененный таким образом, переходит в состояние TaskStatus.RanToCompletion , а не в состояние TaskStatus.Canceled .In many scenarios this is sufficient; however, a task instance that is canceled in this way transitions to the TaskStatus.RanToCompletion state, not to the TaskStatus.Canceled state.

  • Путем создания исключения OperationCanceledException и его передачи в токен, на котором была запрошена отмена.By throwing a OperationCanceledException and passing it the token on which cancellation was requested. Предпочтительным способом сделать это является использование метода ThrowIfCancellationRequested .The preferred way to do this is to use the ThrowIfCancellationRequested method. Задача, отмененная таким образом, переходит в состояние Canceled, которое вызывающий код может использовать для проверки того, что задача ответила на запрос на отмену.A task that is canceled in this way transitions to the Canceled state, which the calling code can use to verify that the task responded to its cancellation request.

В следующем примере показан базовый шаблон для отмены задачи, вызвавшей исключение.The following example shows the basic pattern for task cancellation that throws the exception. Обратите внимание, что токен передается пользовательскому делегату и самому экземпляру задачи.Note that the token is passed to the user delegate and to the task instance itself.

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

Более полный пример см. в подразделе Практическое руководство. Отмена задачи и ее дочерних элементов.For a more complete example, see How to: Cancel a Task and Its Children.

Когда экземпляр задачи обнаруживает исключение OperationCanceledException , созданное пользовательским кодом, он сравнивает токен исключения со связанным токеном (переданным в API-интерфейс, в котором была создана задача).When a task instance observes an OperationCanceledException thrown by user code, it compares the exception's token to its associated token (the one that was passed to the API that created the Task). Если они совпадают и свойство IsCancellationRequested токена возвращает значение true, задача интерпретирует это как подтверждение отмены и переходит в состояние Canceled.If they are the same and the token's IsCancellationRequested property returns true, the task interprets this as acknowledging cancellation and transitions to the Canceled state. Если метод Wait или WaitAll не используется для ожидания задачи, она просто устанавливает состояние Canceled.If you do not use a Wait or WaitAll method to wait for the task, then the task just sets its status to Canceled.

Если ожидается задача, которая переходит в состояние Canceled, создается исключение System.Threading.Tasks.TaskCanceledException (заключенное в исключение AggregateException ).If you are waiting on a Task that transitions to the Canceled state, a System.Threading.Tasks.TaskCanceledException exception (wrapped in an AggregateException exception) is thrown. Обратите внимание, что это исключение указывает на успешную отмену, а не на сбой.Note that this exception indicates successful cancellation instead of a faulty situation. Следовательно, свойство Exception задачи возвращает значение null.Therefore, the task's Exception property returns null.

Если свойство IsCancellationRequested токена возвращает значение false или если токен исключения не соответствует токену задачи, исключение OperationCanceledException обрабатывается как обычное исключение, вызывая переход задачи в состояние Faulted.If the token's IsCancellationRequested property returns false or if the exception's token does not match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state. Кроме того, обратите внимание, что наличие других исключений также приведет к переходу задачи в состояние Faulted.Also note that the presence of other exceptions will also cause the Task to transition to the Faulted state. Состояние завершения задачи можно получить в свойстве Status .You can get the status of the completed task in the Status property.

В некоторых случаях задача может продолжить обработку некоторых элементов после запроса отмены.It is possible that a task may continue to process some items after cancellation is requested.

См. такжеSee also