| 型 | プロパティ | 内容 |
|---|---|---|
| bool | IsCancellationRequested | 取り消し (キャンセル) が要求されているかどうか |
| CancellationToken | Token | このCancellationTokenSourceに関連付けられているCancellationToken |
| メソッド | 機能 |
|---|---|
| Cancel() | キャンセルを要求できる |
| CancelAfter(Int32) | キャンセルするまでの時間を設定できる |
キャンセルを要求する側はCancellationTokenSource.Cancel()を呼び出し、別スレッドの側はそれのCancellationToken.IsCancellationRequestedでキャンセルの要求を検出し処理を中断します。
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task.Run(() =>
{
if (token.IsCancellationRequested)
{
// キャンセルを要求されたならば、処理を抜ける
break;
}
});
// キャンセルを要求する
tokenSource.Cancel();
一度キャンセルを要求したCancellationTokenSourceはその要求を取り消せないため、再度CancellationTokenSourceが必要なときはそのインスタンスを再生成します。
CancellationTokenSourceへの最後の参照を解放する前に、CancellationTokenSource.Dispose()を呼びます。さもなくばガベージ コレクタがFinalize()を呼ぶまで、そのリソースは解放されません。 Dispose() - CancellationTokenSource.Dispose Method (System.Threading) | Microsoft Learn c# - When to dispose CancellationTokenSource? - Stack Overflow
ただしDispose()の後にCancel()を呼ぶとObjectDisposedExceptionが投げられるため、それへの対処が必要です。
キャンセルしたことを呼び出し側へ通知したいならば、OperationCanceledExceptionを投げることでタスクを終了させます。そうするとStatusプロパティはTaskStatus.Canceledとなり、TaskContinuationOptions.OnlyOnCanceledを指定したContinueWith()で継続タスクを実行できます。
OperationCanceledExceptionはタスクのスレッドから投げられないと捕捉されず、継続タスクも実行されません。
CancellationToken.ThrowIfCancellationRequested()を呼び出してキャンセルさせる方法もありますが、これは
if (token.IsCancellationRequested)
throw new OperationCanceledException(token);
とすることと同義です。CancellationToken.ThrowIfCancellationRequested Method (System.Threading) | Microsoft Learn
OperationCanceledExceptionが投げられるTaskは、そのコンストラクタでCancellationTokenを渡します。これはキャンセルできたことをTask.IsCanceledで検証するときにも有用ですが、これらが不要ならば渡す必要はありません。c# - Cancellation token in Task constructor: why? - Stack Overflow
public Task (
Action action,
System.Threading.CancellationToken cancellationToken
);
Task(Action, CancellationToken) - Task Constructor (System.Threading.Tasks) | Microsoft Learn
CancellationTokenをTaskのコンストラクタで渡さないとキャンセルと見なされずStatusはFaultedとなり、継続タスクはOnlyOnCanceledではなくOnlyOnFaultedが実行されます。
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task task = new Task(() =>
{
token.ThrowIfCancellationRequested();
// token.IsCancellationRequested が true ならば、
// OperationCanceledExceptionが投げられる
}, token); // CancellationTokenを渡さねばならない
task.ContinueWith((_task) =>
{
// キャンセルされたときに、ここが実行される
}, TaskContinuationOptions.OnlyOnCanceled);
CancellationTokenSourceを作成するときに時間を指定すると、一定時間後に自動でキャンセルが要求されるようにできます。
指定の時間でキャンセルが要求されるだけで、その時間でキャンセルされるわけではありません。
public CancellationTokenSource (int millisecondsDelay);CancellationTokenSource(Int32) - CancellationTokenSource Constructor (System.Threading) | Microsoft Learn
コンストラクタの呼び出し時点から秒読みが開始され、指定の時間が経過するとToken.IsCancellationRequestedがtrueに設定されます。この時間は、CancellationTokenSource.CancelAfter()で後から変更できます。
int millisecondsDelay = 100;
CancellationTokenSource tokenSource = new CancellationTokenSource(millisecondsDelay);
CancellationToken token = tokenSource.Token;
Task task = new Task(() =>
{
if (token.IsCancellationRequested)
{
}
});
連続する要求に対し、最後の1つだけを処理する方法を考えます。
CancellationTokenSource tokenSource = null;
void Method()
{
CancellationTokenSource newTokenSource = new CancellationTokenSource();
CancellationTokenSource oldTokenSource = Interlocked.Exchange(ref tokenSource, newTokenSource);
if (oldTokenSource != null)
{
oldTokenSource.Cancel(); // キャンセルを要求する
}
try
{
// 待機する
await Task.Delay(1000, newTokenSource.Token); // キャンセルが要求されたならばTaskCanceledExceptionが投げられる
// 何らかの処理
}
catch (TaskCanceledException)
{
}
}