How to cancel a Task in await?
Read up on Cancellation (which was introduced in .NET 4.0 and is largely unchanged since then) and the Task-Based Asynchronous Pattern, which provides guidelines on how to use CancellationToken
with async
methods.
To summarize, you pass a CancellationToken
into each method that supports cancellation, and that method must check it periodically.
private async Task TryTask()
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(TimeSpan.FromSeconds(1));
Task<int> task = Task.Run(() => slowFunc(1, 2, source.Token), source.Token);
// (A canceled task will raise an exception when awaited).
await task;
}
private int slowFunc(int a, int b, CancellationToken cancellationToken)
{
string someString = string.Empty;
for (int i = 0; i < 200000; i++)
{
someString += "a";
if (i % 1000 == 0)
cancellationToken.ThrowIfCancellationRequested();
}
return a + b;
}
Or, in order to avoid modifying slowFunc
(say you don't have access to the source code for instance):
var source = new CancellationTokenSource(); //original code
source.Token.Register(CancelNotification); //original code
source.CancelAfter(TimeSpan.FromSeconds(1)); //original code
var completionSource = new TaskCompletionSource<object>(); //New code
source.Token.Register(() => completionSource.TrySetCanceled()); //New code
var task = Task<int>.Factory.StartNew(() => slowFunc(1, 2), source.Token); //original code
//original code: await task;
await Task.WhenAny(task, completionSource.Task); //New code
You can also use nice extension methods from https://github.com/StephenCleary/AsyncEx and have it looks as simple as:
await Task.WhenAny(task, source.Token.AsTask());