【C#】非同期タスクのキャンセル方法|CancellationTokenの基本

非同期処理を行うとき、ユーザーが操作を取り消した場合や一定時間を過ぎた場合に「処理を途中で止めたい」という場面があります。そのために用意されているのが CancellationToken です。これを利用すると、安全かつ効率的に非同期タスクをキャンセルできます。本記事では CancellationToken の基本的な使い方を解説します。

CancellationTokenの仕組み

CancellationTokenCancellationTokenSource から生成されます。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 をタスクに渡して処理側で監視
  • キャンセルチェックには IsCancellationRequestedThrowIfCancellationRequested を活用
  • タイムアウトや複数トークンの組み合わせも可能

ユーザー体験やシステム効率を高めるために、非同期処理ではキャンセル制御を組み込むのがベストプラクティスです。