Overview
Cancellation allows asynchronous or long-running operations to stop cleanly.
Some objects invoke long-running, cancelable operations. These objects can pass a CancellationToken
to those downstream operation. Downstream operations can pass that same token to other operations. When the cancellation token is invoked, it is a cancellation request; it means that the operation should stop as soon as possible after any required cleanup is performed. A single token can cancel multiple asynchronous invocations.
Creating
Cancellation tokens are created with CancellationTokenSource
objects. The CTS’s Token
property returns the CancellationToken
(CT) that is signaled when the CTS’s Cancel
method is called:
var cts = new CancellationTokenSource();
string result = await DownloadStringTaskAsync(url, cts.Token);
… // at some point later, potentially on another thread
cts.Cancel();
CancellationTokenSource
is disposable.
Listening for and Processing Cancellation
CancellationToken
has its IsCancellationRequested
property set to true
once Cancel
is called on the CTS. Poll this value at interval to check for a cancellation request.
This property can only be set once, so the CT cannot be reused after being canceled.
After receiving a cancellation request, perform cleanup, then either:
- return, or;
- call
CancellationToken.ThrowIfCancellationRequest()
.
Option 2 throws an OperationCanceledException
. This exception can be caught by upstream operations to signal that cancellation was requested downstream.
Pass CancellationToken.None
to a method to indicate that cancellation will never be requested. The method will then optimize.
Canceling Tasks After a Period of Time [ Documentation]
Use CancellationTokenSource
’s CancelAfter
method to schedule the cancellation of any tasks that are not complete within a period of time:
static async Task Main()
{
Console.WriteLine("Application started.");
try
{
s_cts.CancelAfter(3500); // 3500 milliseconds
await SumPageSizesAsync();
}
catch (OperationCanceledException) // An OCE is thrown when a cancellation is triggered.
{
Console.WriteLine("\nTasks cancelled: timed out.\n");
}
finally
{
s_cts.Dispose();
}
Console.WriteLine("Application ending.");
}
Registering Callbacks for Cancellation Requests [ Documentation] [ Documentation]
You can register a delegate that is invoked when Cancel
is called on a CancellationToken
:
public void SomeMethod(CancellationToken token)
{
// ...do some work...
token.Register(() =>
{
Console.WriteLine("Cancellation requested!");
CancelMethod();
});
}
public void CancelMethod()
{
// clean up work...
}
Even if cancellation has already been requested when the callback is registered, the callback is still guaranteed to be called.
Other Notes
- For methods that cannot be canceled, do not provide an overload that accepts a
CancellationToken
. - If a cancellation request results in work ending prematurely, the method returns a task in
Canceled
state. - Code that is asynchronously waiting for a task that is canceled receives a
OperationCanceledException
. - Code blocked waiting through
Wait
orWaitAll
on a task that is canceled continues to run with an exception. - If cancellation is requested before the async method starts, the async method should return
Canceled
task. - If cancellation is requested after the async method starts, the async method decides whether to cancel. Cancellation is a request.
- If cancellation is requested but a result/exception produced, the task ends in
RanToCompletion
orFaulted
state.