Zrušení úkolu

Třídy System.Threading.Tasks.Task podporují System.Threading.Tasks.Task<TResult> zrušení pomocí tokenů zrušení. Další informace najdete v tématu Zrušení ve spravovaných vláknech. V třídách úkolů zahrnuje zrušení spolupráci mezi delegátem uživatele, který představuje operaci zrušitelnou a kód, který požadoval zrušení. Úspěšné zrušení zahrnuje žádost o kód volající metodu CancellationTokenSource.Cancel a delegát uživatele ukončuje operaci včas. Operace může být ukončena pomocí jedné z těchto možností:

  • Vrácením od delegáta. V mnoha scénářích je tato možnost dostatečná. Instance úlohy, která je tímto způsobem zrušena, se ale převede do TaskStatus.RanToCompletion stavu, nikoli do TaskStatus.Canceled stavu.

  • OperationCanceledException Vyvoláním a předáním tokenu, na kterém bylo požadováno zrušení. Upřednostňovaným způsobem provedení je použití ThrowIfCancellationRequested metody. Úkol, který se tímto způsobem zruší, přejde do zrušeného stavu, který může volající kód použít k ověření, že úkol odpověděl na žádost o zrušení.

Následující příklad ukazuje základní vzor pro zrušení úkolu, který vyvolá výjimku:

Poznámka

Token se předá delegátu uživatele a instanci úlohy.

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

Úplný příklad najdete v tématu Postupy: Zrušení úkolu a jeho podřízených položek.

Když instance úlohy sleduje OperationCanceledException vyvolání uživatelským kódem, porovná token výjimky s přidruženým tokenem (ten, který byl předán rozhraní API, které vytvořilo úlohu). Pokud jsou tokeny stejné a vlastnost tokenu IsCancellationRequested vrátí true, úloha to interpretuje jako potvrzení zrušení a přechody do zrušeného stavu. Pokud k čekání na úkol nepoužíváte metodu Wait nebo WaitAll ji nepoužíváte, nastaví úkol jeho stav na Canceled.

Pokud čekáte na úkol, který přejde do zrušeného stavu, System.Threading.Tasks.TaskCanceledException vyvolá se výjimka (zabalená v výjimce AggregateException ). Tato výjimka označuje úspěšné zrušení místo chybné situace. Proto vlastnost úkolu Exception vrátí null.

Pokud vlastnost tokenu IsCancellationRequested vrátí false nebo pokud token výjimky neodpovídá tokenu úkolu, OperationCanceledException je považován za normální výjimku, což způsobí, že úloha přejde do chybného stavu. Přítomnost dalších výjimek také způsobí, že úloha přejde do chybného stavu. Stav dokončeného úkolu můžete získat ve Status vlastnosti.

Je možné, že úkol může po vyžádání zrušení pokračovat ve zpracování některých položek.

Viz také