Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Non Blocking C# Task Cancelling

0.00/5 (No votes)
13 May 2014 1  
Non blocking C# task cancelling

In our previous sample snippet, Cancel a Loop in a Task with CancellationTokens in C#, I try to explain how we can get out of a looping C# task, but a problem may arise from that situation. If we were to wait for any result out of that task, we would be blocking the calling thread until the task returned, which is not good if we are on the main thread. We would be locking our UI and might crash our application.

So I’ve been testing different ways to get out of that loop without causing any trouble, and you can achieve what we want in many different ways.

So, to begin with, I think I would correctly assume that it is only necessary to wait for a task to complete if that task will return something. If there is no return value, why would we want to call wait on it? We can just break out of it, correct me if I’m wrong. If we have a return value, then it is necessary to surround the wait call on the task with try/catch to receive its result. But then again, we can avoid the locking here with a continuation task, which will create and start the task after the first one completes, giving us the result from the previous task to work with.

If by any chance we want to wait for any result, then we must use the wait method, locking the calling thread. This will lead to the same problem, blocking that thread and if this thread is the main thread that holds our UI, it's bad for the user experience and might lead to crashing our application.

First solution, to correct this.
Have a Task, create the Working Task, and wait for it to finish. So you’ll have two tasks in the end and you won’t be locking the UI thread. But, say you have a UI Button to start these chaining tasks. You’ll be creating as many tasks as you click that button. Unless you implement a way to only have one running at any time. You could do that, by sending a cancellation token, in which you kill the task before re-creating a new one. But this could loop back to our blocking problem.

Another way of doing this is going Async/Await on the methods.

For a method that doesn’t return any value, we just have to change our code to break out of our loop when the cancellation is requested, instead of calling ThrowIfCancelledRequired(), we just check if the Cancellation is requested and just break out. As we’re not waiting for any result, we just let the task finish. Using this idea, we could even remove the need of the cancellation token. We could use a volatile bool variable to control our cancellation for us. But I find it more ‘good practice’ to use the cancellation token. I don’t really know how the volatile access performs between multiple tasks, so I’m keeping the Cancellation Token. Here’s a sample code:

CancellationTokenSource _cts;
volatile bool _run = true;

public void Start( )
{
    // do something
    _cts = new CancellationTokenSource();
    var token = _cts.Token;
 
    var t = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Start");
        while (true)
        {
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Break");
                break;
            }
             
            Console.WriteLine("."); // just to show progress from task.
            Thread.Sleep(1000);
        }
    }, token);
}

public void Cancel( )
{
    Console.WriteLine("Cancel");
    //_run = false;
 
    // stop that.
    if( _cts != null )
        _cts.Cancel();
}

void Main( )
{
    Start( );
    
    Console.ReadLine();
    Cancel();
}

This will output something like this after pressing Enter after 4 seconds:

Start
.
.
.
.
Cancel
Break

Note that _cts is a member variable of the class where Start is being called so it can be accessed in the Cancel method. Back to our first solution, if we were to declare a volatile bool _run variable as commented on the Cancel method, we would have to, firstly, uncomment that line to change the value to false, and change the true on the Start’s method while loop.

Remember that I only break out of the loop with break because the method does not return any value to the calling thread. Otherwise, I would have to try/catch that value.

I hoped you enjoyed this and if you’ve learned something today, my work is done. Please leave a comment or suggestion. <img alt="Smile | :) " class="wp-smiley" src="http://www.mikeadev.net/wp-includes/images/smilies/icon_smile.gif" />

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here