Home > Blockchain >  CancellationToken not working with zero timeout
CancellationToken not working with zero timeout

Time:11-16

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?

CodePudding user response:

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 its 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 cant rely on a 0 second timeout to give you immediate confirmation via IsCancellationRequested. You will need to rethink your problem.

CodePudding user response:

The CancellationTokenSource.CancelAfter method (source code) does not include a special handling for the TimeSpan.Zero value, so the cancellation is scheduled to the ThreadPool with a Timer having zero timeout. This results to a race condition, which the synchronous while (!linkedCancellationTokenSource.IsCancellationRequested) loop wins most of the time. The only solution I can think of, taking into account that the implementation of the DoIdleWait method is not under your control, is to not invoke this method if you know that the timeout is zero.

  • Related