Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Canceled task also appears as completed

I'm playing around with async-await and cancellation to get some more understanding on the matter. For this I have made the following console application:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncTest
{
    class Program
    {
        private static CancellationTokenSource _cancellationTokenSource;
        private static CancellationToken _cancellationToken;

        static void Main(string[] args)
        {
            Console.CancelKeyPress += myHandler;

            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;

            var task = DoWorkAsync(_cancellationToken).ContinueWith(ContinueMethod);
            task.Wait();

            Console.ReadLine();
        }

        protected static void myHandler(object sender, ConsoleCancelEventArgs args)
        {
            if (_cancellationToken.CanBeCanceled)
            {
                _cancellationTokenSource.Cancel();
            }
            args.Cancel = true;
        }

        static void ContinueMethod(Task task)
        {
            if (task.IsCanceled)
            {
                Console.WriteLine("The task was canceled");
            }

            if (task.IsCompleted)
            {
                Console.WriteLine("The task completed successfully");
            }

            if (task.IsFaulted)
            {
                if (task.Exception != null)
                {
                    var exceptions = task.Exception.Flatten().InnerExceptions;
                    foreach (var exception in exceptions)
                    {
                        Console.WriteLine(exception.Message);
                    }
                }
                Console.WriteLine("The task failed");
            }
        }

        static async Task DoWorkAsync(CancellationToken cancellationToken)
        {
            await Task.Run(() => DoWork(cancellationToken), cancellationToken);
        }

        static void DoWork(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            Console.WriteLine("DoWork() is started");

            // Uncomment the following line of code to put the task in a 'faulted' state
            //throw new Exception();

            for (var count = 0; count < 10; count++)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    Console.WriteLine("Get a cancelation request");
                    cancellationToken.ThrowIfCancellationRequested();
                }
                else
                {
                    Thread.Sleep(500);
                    Console.WriteLine("Count : " + count);
                }
            }
            Console.WriteLine("DoWork() is finished");
        }
    }
}

When I let the application complete, I correctly receive the "The task completed successfully" message.

Now when I press CTRL+C, which triggers a cancel on the started task (see interception through myHandler), I correctly get the "The task was canceled" message. But I also get the "The task completed successfully" message. I was not expecting the task to also show up as complete, since I canceled it. In case I uncomment the throw new Exception(); line in the DoWork() method, I correctly receive the "The task failed" message, but also the "The task completed successfully" message. Am I wrong in my assumption and is this as designed? Or am I missing something else entirely?

I could off course work around this by adding an additional check as follows:

if (task.IsCompleted && !task.IsCanceled)
{
    Console.WriteLine("The task completed successfully");
}

But I'm not sure if this is the correct way or if something else in my program is causing this completed state.

Thanks in advance for your input and/or clarification on this matter.

like image 272
Kevin D Avatar asked May 31 '26 19:05

Kevin D


2 Answers

The documentation of Task.IsCompleted says

IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled.

So IsCompleted tells you at least that the Task is not running any more. It does not indicate if the Task completed successfully, failed or was cancelled.

like image 144
Jehof Avatar answered Jun 02 '26 07:06

Jehof


Use Task.IsCompletedSuccessFully

like image 34
Shishir Gupta Avatar answered Jun 02 '26 09:06

Shishir Gupta