Search code examples
c#task-parallel-librarycancellationtokensourcecancellation-token

Wait for request of CancellationToken cancellation


How can I pause the executing until the cancellation is requested?

var cts = new CancellationTokenSource();

Task.Run(() =>
{
    // Wait for the Cancel...

    Console.WriteLine("Canceled!");
});

Console.ReadKey();

cts.Cancel();

Console.ReadKey();

Solution

  • The CancellationTokenSource uses a ManualResetEvent internally and you can just wait for the exposed WaitHandle to pause the execution until it is set.

    var cts = new CancellationTokenSource();
    
    Task.Run(() =>
    {
        WaitHandle.WaitAny(new[] { cts.Token.WaitHandle });
    
        Console.WriteLine("Canceled!");
    });
    
    Console.ReadKey();
    
    cts.Cancel();
    
    Console.ReadKey();
    

    This is the WaitHandle defined in the CancellationTokenSource:

    ManualResetEvent mre = new ManualResetEvent(false);
    if (Interlocked.CompareExchange(ref m_kernelEvent, mre, null) != null)
    {    
        ((IDisposable)mre).Dispose();
    }
    
    // There is a ---- between checking IsCancellationRequested and setting the event.
    // However, at this point, the kernel object definitely exists and the cases are:
    //   1. if IsCancellationRequested = true, then we will call Set()
    //   2. if IsCancellationRequested = false, then NotifyCancellation will see that the event exists, and will call Set().
    if (IsCancellationRequested)
        m_kernelEvent.Set();
    
    return m_kernelEvent;
    

    And the Token just returns the handle from the source (has an internal variable referencing it).

    Another option is to register the Token callback and use your own ManualResetEvent:

    var cts = new CancellationTokenSource();
    
    Task.Run(() =>
    {
        var mre = new ManualResetEvent(false);
    
        var registration = cts.Token.Register(() => mre.Set());
    
        using (registration)
        {
            mre.WaitOne();
    
            Console.WriteLine("Canceled!");
        }
    });
    
    Console.ReadKey();
    
    cts.Cancel();
    
    Console.ReadKey();
    

    Examples: https://blogs.msdn.microsoft.com/pfxteam/2009/05/22/net-4-cancellation-framework/