Async .NET · Lesson 6

Cancelling an awaited timer

Use a cancellable API instead of polling shared flags.

How it works

Task.Delay accepts a cancellation token and completes as cancelled when cancellation is requested before its timer finishes. The delay in this example is long, but the source is cancelled immediately, so the program does not wait for that duration. Await throws an OperationCanceledException, which the caller handles as an expected stop. Cancellation and failure should remain distinguishable in the user interface: a person pressing Stop did not necessarily encounter a broken runtime.

The token is a request channel, not a thread abort mechanism, and it cannot interrupt a synchronous infinite loop that never checks it.

Pass CancellationToken.None and explain why this particular delay would no longer stop when the unrelated source is cancelled. Restore the source token before running the long delay.

A working example

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

using var source = new CancellationTokenSource();
var waiting = Task.Delay(TimeSpan.FromMinutes(1), source.Token);
source.Cancel();
try { await waiting; }
catch (OperationCanceledException) { Console.WriteLine("timer stopped"); }

Expected output

timer stopped
Try this
Give cancellable operations the token instead of checking a flag repeatedly.