Reputation: 915
I've created a little demo project to help me understand how I can use Cancellation Tokens. I understand that you cancel a token and check if a cancellation has been requested, but is there a way that I can check whether the cancellation has been realised? In my example below, I don't want to run Work() again until DoWork() has finished running.
public class Program
{
public static CancellationTokenSource tokenSource;
private static void Main(string[] args)
{
while (true)
{
Work();
}
}
public static async void Work()
{
tokenSource = new CancellationTokenSource();
Console.WriteLine("Press any key to START doing work");
Console.ReadLine();
Console.WriteLine("Press any key to STOP doing work");
DoWork(tokenSource.Token);
Console.ReadLine();
Console.WriteLine("Stopping...");
tokenSource.Cancel();
}
public static async void DoWork(CancellationToken cancelToken)
{
while (true)
{
Console.WriteLine("Working...");
await Task.Run(() =>
{
Thread.Sleep(1500);
});
if (cancelToken.IsCancellationRequested)
{
Console.WriteLine("Work Cancelled!");
return;
}
}
}
}
Upvotes: 4
Views: 11799
Reputation: 44026
You will make the most out of a CancellationToken
if all your operations are asynchronous and cancellable. This way cancelling the token will have immediate effect. You won't have to wait for a Thread.Sleep
or other blocking call to complete.
public static async Task DoWork(CancellationToken cancellationToken)
{
while (true)
{
await Console.Out.WriteLineAsync("Working...");
await Task.Delay(1500, cancellationToken);
}
}
In this example the token is passed only to Task.Delay
, because the WriteLineAsync
is not cancellable on .NET Framework (it is on .NET Core).
An OperationCanceledException
will be raised by Task.Delay
when the token is cancelled.
Upvotes: 4
Reputation: 42360
You typically don't want to make your DoWork
function async void
-- make it async Task
instead. That way you can see when it's completed (or been cancelled).
You also probably want to use cancelToken.ThrowIfCancellationRequested()
. This throws an OperationCanceledException
, which you can catch.
public class Program
{
public static CancellationTokenSource tokenSource;
private static async Task Main(string[] args)
{
while (true)
{
await Work();
}
}
public static async Task Work()
{
tokenSource = new CancellationTokenSource();
Console.WriteLine("Press any key to START doing work");
Console.ReadLine();
Console.WriteLine("Press any key to STOP doing work");
var task = DoWork(tokenSource.Token);
Console.ReadLine();
Console.WriteLine("Stopping...");
tokenSource.Cancel();
try
{
await task;
}
catch (OperationCanceledException)
{
// Task was cancelled
}
}
public static async Task DoWork(CancellationToken cancelToken)
{
while (true)
{
Console.WriteLine("Working...");
await Task.Run(() =>
{
Thread.Sleep(1500);
});
cancelToken.ThrowIfCancellationRequested();
}
}
}
This code relies on "async main", which was introduced in C# 7. If you don't have this, you can write your Main method as:
private static void Main(string[] args)
{
while (true)
{
Work().Wait();
}
}
Upvotes: 6