Cancelling Tasks in .NET 4.0

Posted by: Suprotim Agarwal , on 4/15/2010, in Category .NET Framework
Views: 100108
Abstract: In one of the previous articles Parallel Tasks in .NET 4.0 (Part II) – Methods that Return value, we used the Task(TResult) class which represents an asynchronous operation that can return a value. In this article, we will see how to cancel a task/operation.
In one of the previous articles Parallel Tasks in .NET 4.0 (Part II) – Methods that Return value, we used the Task(TResult) class which represents an asynchronous operation that can return a value. In this article, we will see how to cancel a task/operation.
.NET 4.0 introduces a lightweight struct called the CancellationToken that provides a mechanism to cancel synchronous and asynchronous operations. Here are some important members of this struct:
isCancellationRequested - a Boolean property that can be polled by the code to find out if it has been cancelled or the cancellation has been requested
Register - to register a delegate for a callback when a cancellation request has been made
We use an instance of the CancellationTokenSource class to get a cancellation token. What I liked primarily about this Cancellation model is that the cancellation token can be passed freely to the listeners. So cancelling the token is cleanly separated from the ability to consume a request for cancellation. Here are the steps required to cancel a task:
1. We first create the cancellation token(cToken) using the CancellationTokenSource class.
2. The cancelable task(GenerateNumbers) is then created by passing the cancellation token to Task<>.Factory.StartNew().
3. We then use the Register() method to register a delegate(cancelNotification) to notify us when a cancellation request has been made.
4. On pressing 1, the request for a task to be cancelled is made using the CancellationTokenSource.Cancel() method, and the delegate notifies us that the cancellation was requested.
Let us illustrate the steps shown above and understand the process of cancelling a task with the help of an example. The code has comments which explains what’s going on
C#
using System;
using System.Threading.Tasks;
using System.Threading;
 
namespace CancelTask
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press 1 to cancel task");
            var cTokenSource = new CancellationTokenSource();
            // Create a cancellation token from CancellationTokenSource
            var cToken = cTokenSource.Token; 
            // Create a task and pass the cancellation token
            var t1 = Task<int>.Factory.StartNew(()
                => GenerateNumbers(cToken), cToken);
 
            // to register a delegate for a callback when a
            // cancellation request is made
            cToken.Register(() => cancelNotification());
 
            // If user presses 1, request cancellation.
            if (Console.ReadKey().KeyChar == '1')
            {
                // cancelling task
                cTokenSource.Cancel();
            }
            Console.ReadLine();
        }
 
        static int GenerateNumbers(CancellationToken ct)
        {
            int i;
            for (i = 0; i < 10; i++)
            {
                Console.WriteLine("Method1 - Number: {0}", i);
                Thread.Sleep(1000);
                // poll the IsCancellationRequested property
                // to check if cancellation was requested
                if (ct.IsCancellationRequested)
                {
                    break;
                }
 
            }
            return i;
        }
 
        // Notify when task is cancelled
        static void cancelNotification()
        {
            Console.WriteLine("Cancellation request made!!");
        }
    }
}
 
VB.NET (Converted)
Imports System
Imports System.Threading.Tasks
Imports System.Threading
 
Namespace CancelTask
      Friend Class Program
            Sub Main(ByVal args() As String)
                  Console.WriteLine("Press 1 to cancel task")
                  Dim cTokenSource = New CancellationTokenSource()
                  ' Create a cancellation token from CancellationTokenSource
                  Dim cToken = cTokenSource.Token
                  ' Create a task and pass the cancellation token
                  Dim t1 = Task(Of Integer).Factory.StartNew(Function() GenerateNumbers(cToken), cToken)
 
                  ' to register a delegate for a callback when a
                  ' cancellation request is made
                  cToken.Register(Sub() cancelNotification())
 
                  ' If user presses 1, request cancellation.
                  If Console.ReadKey().KeyChar = "1"c Then
                        ' cancelling task
                        cTokenSource.Cancel()
                  End If
                  Console.ReadLine()
            End Sub
 
            Private Shared Function GenerateNumbers(ByVal ct As CancellationToken) As Integer
                  Dim i As Integer
                  For i = 0 To 9
                        Console.WriteLine("Method1 - Number: {0}", i)
                        Thread.Sleep(1000)
                        ' poll the IsCancellationRequested property
                        ' to check if cancellation was requested
                        If ct.IsCancellationRequested Then
                              Exit For
                        End If
 
                  Next i
                  Return i
            End Function
 
            ' Notify when task is cancelled
            Private Shared Sub cancelNotification()
                  Console.WriteLine("Cancellation request made!!")
            End Sub
      End Class
End Namespace
 
Here’s the output:
Output
This article demonstrated a fairly simple example of cancelling a task. In the forthcoming articles, we will see some more advanced scenarios. The entire source code of this article can be downloaded over here
I hope you liked the article and I thank you for viewing it.
Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Suprotim Agarwal, ASP.NET Architecture MVP, MCSD, MCAD, MCDBA, MCSE, is the CEO of A2Z Knowledge Visuals Pvt. He primarily works as an Architect Consultant and provides consultancy on how to design and develop .NET centric database solutions.

Suprotim is the founder and primary contributor to DotNetCurry, DNC .NET Magazine, SQLServerCurry and DevCurry. He has also written an EBook 51 Recipes using jQuery with ASP.NET Controls. and is authoring another one at The Absolutely Awesome jQuery CookBook.

Follow him on twitter @suprotimagarwal


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Thai on Sunday, September 30, 2012 12:13 AM
Thanks for your post. It's great.
I assume I have a web server to call to a WCF service to do somethings. The server can send a request to cancel a running task in WCF service.
Can I send a CancellationToken to the WCF service to cancel a task ?

Many thanks,
Thai
Comment posted by Thai on Sunday, September 30, 2012 1:57 AM
Thanks for your post. It's great.
I assume I have a web server to call to a WCF service to do somethings. The server can send a request to cancel a running task in WCF service.
Can I send a CancellationToken to the WCF service to cancel a task ?

Many thanks,
Thai
Comment posted by Himanshu on Tuesday, January 29, 2013 11:43 PM
Hi

From Main Task (t1  like GenerateNumbers)if the method itself generates 'n' number of tasks i.e. GenerateNumbers method having loop generating new tasks from inside. If cancellation of main task is called what will happen to child tasks generated from inside method GenerateNumbers.



Comment posted by Pradeep on Thursday, June 13, 2013 5:01 AM
I found your example to be a bit flawed.
Even though you are breaking from the loop, the t1.IsCanceled is false.
In order to cancel the task, it is recommended to call
cToken.ThrowIfCancellationRequested() in order to update IsCanceled to true.

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel