Search code examples
c#cancellationtokensourcecancellation-token

CancellationToken not working with zero timeout


I have a code which depends on a cancellation token with zero timeout to bail out early. This is the snippet

using System;
using System.Threading;

namespace ConsoleApp2
{
    class Program
    {
        void DoIdleWait(TimeSpan timeout, CancellationToken cancellationToken)
        {
            var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            linkedCancellationTokenSource.CancelAfter(timeout);

            while (!linkedCancellationTokenSource.IsCancellationRequested)
            {
                Console.WriteLine("Waiting");
            }
        }

        static void Main(string[] args)
        {
            var prog = new Program();
            var cts = new CancellationTokenSource();
            cts.CancelAfter(TimeSpan.FromSeconds(2));
            prog.DoIdleWait(TimeSpan.Zero, cts.Token);
        }
    }
}

Since the timeout is zero, I expect it not to enter the if block, but it's not doing that. Any idea why this is happening? Also, any way to achieve what I am trying to do?


Solution

  • To paraphrase the question:

    Why, when you create a linked CancellationTokenSource from a CancellationTokenSource with a registered timeout, then set the resultant token source with a timeout of zero, does it not know it should be cancelled?

    More paraphrasing:

    After all, zero is zero and it should know it's cancelled.

    The answer is, because a CancellationTokenSource.CancelAfter tries to register a timer callback, which attempts to set the resolution to zero milliseconds which it cannot possibly honor.

    So in turn, you get the minimum resolution any standard timing mechanism can give you without using CPU spins, which is about 5+ milliseconds.

    There are likely other solutions to your problem, however, in short you can't rely on a 0 second timeout to give you immediate confirmation via IsCancellationRequested. You will need to rethink your problem.