非同期処理を行うとき、ユーザーが操作を取り消した場合や一定時間を過ぎた場合に「処理を途中で止めたい」という場面があります。そのために用意されているのが CancellationToken
です。これを利用すると、安全かつ効率的に非同期タスクをキャンセルできます。本記事では CancellationToken
の基本的な使い方を解説します。
CancellationTokenの仕組み
CancellationToken
は CancellationTokenSource
から生成されます。Cancel()
メソッドを呼び出すことで、トークンを監視している非同期処理に「キャンセル要求」が通知されます。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var cts = new CancellationTokenSource();
var token = cts.Token;
var task = DoWorkAsync(token);
// 2秒後にキャンセル要求
await Task.Delay(2000);
cts.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("タスクはキャンセルされました");
}
}
static async Task DoWorkAsync(CancellationToken token)
{
for (int i = 0; i < 5; i++)
{
token.ThrowIfCancellationRequested(); // キャンセル要求を確認
Console.WriteLine($"処理中: {i}");
await Task.Delay(1000, token); // キャンセル可能な待機
}
}
}
キャンセルの確認方法
タスク側では以下のようにキャンセルを確認します。
token.IsCancellationRequested
… キャンセル要求が出ているか確認token.ThrowIfCancellationRequested()
… 要求があれば例外を投げるTask.Delay(..., token)
のようにキャンセル対応 API を利用
タイムアウトによるキャンセル
CancellationTokenSource
にはタイムアウトを設定できます。指定時間が経過すると自動的にキャンセルが発行されます。
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await DoWorkAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("タイムアウトでキャンセルされました");
}
複数のキャンセル条件を組み合わせる
CancellationTokenSource.CreateLinkedTokenSource
を利用すると、複数のキャンセル要因をまとめて扱えます。例えば「ユーザー操作によるキャンセル」と「タイムアウト」に同時対応可能です。
var userCts = new CancellationTokenSource();
var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
userCts.Token, timeoutCts.Token);
await DoWorkAsync(linkedCts.Token);
まとめ
CancellationToken
を利用すると非同期タスクを効率的に制御できます。
CancellationTokenSource
でキャンセル要求を発行CancellationToken
をタスクに渡して処理側で監視- キャンセルチェックには
IsCancellationRequested
やThrowIfCancellationRequested
を活用 - タイムアウトや複数トークンの組み合わせも可能
ユーザー体験やシステム効率を高めるために、非同期処理ではキャンセル制御を組み込むのがベストプラクティスです。