タスクのキャンセル
System.Threading.Tasks.Task クラスと System.Threading.Tasks.Task<TResult> クラスは、キャンセル トークンを使用したキャンセルをサポートします。 詳細については、「マネージド スレッドのキャンセル」を参照してください。 Task クラスのキャンセル処理には、キャンセル可能な操作を表すユーザー デリゲートと、キャンセルを要求したコードとの連携が含まれます。 キャンセル処理が正常に実行されるには、要求コードが CancellationTokenSource.Cancel メソッドを呼び出し、ユーザー デリゲートが操作を適時に終了する必要があります。 次のオプションのいずれかを使用して操作を終了できます。
デリゲートから戻ります。 シナリオの多くは、この方法で充分です。 ただし、この方法でキャンセルされたタスク インスタンスは、TaskStatus.Canceled 状態ではなく、TaskStatus.RanToCompletion 状態に遷移します。
OperationCanceledException をスローして、これをキャンセルの要求に使用したトークンに渡します。 これを行うための方法としては、ThrowIfCancellationRequested メソッドが推奨されます。 この方法でキャンセルされたタスクは Canceled 状態に遷移します。呼び出し元のコードでは、これを利用して、タスクがキャンセル要求に応答したことを確認します。
次の例は、例外のスローが発生するタスクのキャンセルの基本的なパターンを示しています。
注意
トークンは、ユーザー デリゲートとタスク インスタンスに渡されます。
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
を返す場合、タスクによってこれがキャンセルの確認であると解釈され、タスクは Canceled 状態に遷移します。 タスクの待機に Wait メソッドまたは WaitAll メソッドを使用しない場合は、タスクによってその状態が Canceled に設定されます。
タスクが Canceled 状態に遷移するのを待っている場合、System.Threading.Tasks.TaskCanceledException 例外 (AggregateException 例外によってラップされている) がスローされます。 この例外は、障害が発生している状況を示しているのではなく、正常なキャンセルを示してします。 このため、タスクの Exception プロパティは null
を返します。
トークンの IsCancellationRequested プロパティが false
を返す場合、または例外のトークンがタスクのトークンに一致しない場合、OperationCanceledException は通常の例外のように扱われます。これにより、タスクは Faulted 状態に遷移します。 他の例外が存在する場合も、タスクは Faulted 状態に遷移します。 完了したタスクの状態は Status プロパティで取得できます。
キャンセルが要求された後も、タスクによる一部の項目の処理が継続する可能性があります。
関連項目
.NET