Monitoring Task cancellation in .NET C# using a Wait handle
February 21, 2014 2 Comments
You cannot directly interrupt a Task in .NET while it’s running. You can do it indirectly through the CancellationTokenSource object. This object has a CancellationToken property which must be passed into the constructor of the Task:
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = cancellationTokenSource.Token;
The cancellation token can be used as follows:
// create the task Task task = Task.Factory.StartNew(() => { for (int i = 0; i < 100000; i++) { if (cancellationToken.IsCancellationRequested) { Console.WriteLine("Task cancelled, must throw exception."); throw new OperationCanceledException(cancellationToken); } else { Console.WriteLine(i); } } }, cancellationToken);
We simply count up to 100000 in the Task body. Note the IsCancellationRequested property of the token. We monitor within the loop whether the task has been cancelled.
The cancellation token has a property called WaitHandle which has a method called WaitOne(). This method blocks until the Cancel() method is called on the token source provided in the Task constructor. It can be used by setting up another Task which calls the WaitOne method which blocks until the first Task has been cancelled:
Task secondTask = Task.Factory.StartNew(() => { cancellationToken.WaitHandle.WaitOne(); Console.WriteLine("WaitOne called."); });
You can cancel the task by calling the Cancel() method of the token like this:
cancellationTokenSource.Cancel();
Note that this method only signals the wish to cancel a task. .NET will not actively interrupt the task, you’ll have to monitor the status through the IsCancellationRequested property. It is your responsibility to stop the task. In this example we throw an OperationCanceledException which is a must in order to correctly acknowledge the cancellation. If you forget this step then the task status will not be set correctly. Once the task has been requested the stop it cannot be restarted.
If that’s all you want to do, i.e. throw an OperationCanceledException, then there’s a shorter version:
cancellationToken.ThrowIfCancellationRequested();
This will perform the cancellation check and throw the exception in one step. The loop can thus be simplified as follows:
Task task = Task.Factory.StartNew(() => { for (int i = 0; i < 100000; i++) { //shorthand cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine(i); } }, cancellationToken);
View the list of posts on the Task Parallel Library here.
Starting a new thread and then blocking it is inefficient. Check https://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx for how to convert WaitHandle to Task.
Thanks for your update. //Andras