タスクのキャンセル

System.Threading.Tasks.Task クラスおよび System.Threading.Tasks.Task<TResult> クラスは、.NET Framework 4 の新機能であるキャンセル トークンを使用したキャンセルをサポートしています。 詳細については、「キャンセル」を参照してください。 Task クラスのキャンセル処理では、キャンセル可能な操作を表すユーザー デリゲートとキャンセルを要求したコードとの間の連携が必要となります。キャンセル処理を正常に完了するには、CancellationTokenSource.Cancel メソッドを呼び出す要求コードと、操作を適切に終了するユーザー デリゲートが必要です。 次のオプションのいずれかを使用して操作を終了できます。

  • デリゲートから戻ります。 多くの場合、この処理で十分ですが、この方法で "取り消された" タスク インスタンスは、Canceled 状態ではなく RanToCompletion 状態に遷移します。

  • OperationCanceledException をスローし、これをキャンセルが要求されたトークンに渡します。 これを行うには、ThrowIfCancellationRequested メソッドを使用する方法をお勧めします。 この方法で取り消されたタスクは Canceled 状態に遷移し、タスクがキャンセル要求に応答したことを確認するために呼び出し元のコードによって使用されます。

次の例は、例外をスローするタスクのキャンセルの基本的なパターンを示しています。 ユーザー デリゲートとタスク インスタンス自体にトークンが渡されることに注意してください。

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
        End Try

        Console.ReadKey()
    End Sub
End Module
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // 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 StartNew.

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch:
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }

        Console.ReadKey();
    }
}

この例より完全なコード例については、「方法: タスクとその子を取り消す」を参照してください。

タスク インスタンスがユーザー コードによってスローされた OperationCanceledException を確認した場合は、例外のトークンと関連付けられたトークン (タスクを作成した API に渡されたトークン) とを比較します。 これらのトークンが同一であり、トークンの IsCancellationRequested プロパティから true が返されると、タスクはこれをキャンセルの受信確認と解釈し、Canceled 状態に遷移します。 Wait メソッドまたは WaitAll メソッドを使用してタスクを待機しない場合、タスクの状態は Canceled に設定されます。

タスクが Canceled 状態に遷移するのを待っていると、TaskCanceledException (AggregateException でラップされている) が生成されてスローされます。 この例外は、障害のある状況ではなく、正常なキャンセル処理を示すことに注意してください。 このため、タスクの Exception プロパティは null を返します。

トークンの IsCancellationRequested プロパティが false を返した場合、または例外のトークンがタスクのトークンと一致しない場合、OperationCanceledException は標準の例外のように扱われるため、タスクは Faulted 状態に遷移します。 他の例外が存在する場合も、タスクが Faulted 状態に遷移することに注意してください。 完了したタスクの状態は Status プロパティで取得できます。

キャンセルが要求された後も、タスクが一部の項目の処理を継続する可能性があります。

参照

処理手順

方法: タスクとその子を取り消す

その他の技術情報

キャンセル