Click here to Skip to main content
Click here to Skip to main content

Non Blocking C# Task Cancelling

, 13 May 2014
Rate this:
Please Sign up or sign in to vote.
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 […]

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 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 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, its 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 don’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. :)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mikea15
Software Developer Cinder Interactive
Portugal Portugal
I am a regular guy who likes to design and write software and games. I'm currently living in Covilhã, Portugal, where I'm finishing my MSc in Computer Science and Engineering.
 
In my spare time I develop and design video games for PC and mobile platforms using Unity3D. I also like to develop tools to help developers.
 
I also like to workout, play sports, go to the movies and hangout with my friends.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 13 May 2014
Article Copyright 2014 by Mikea15
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid