タスクのキャンセル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. Task クラスのキャンセル処理では、キャンセル可能な操作を表すユーザー デリゲートと、キャンセルを要求したコードが連携します。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