Why CancellationTokenSource hangs an application

让人想犯罪 __ 提交于 2020-11-29 02:51:14

问题


Here is simple code piece that hangs and never ends:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        Console.CancelKeyPress += (_, __) => 
            cancellationTokenSource.Cancel();
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}

The problem is Just before close lines gets never executed. My first thought was "maybe it's because of closure on KeyPress" so I have rewritten it in following manner:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        void Foo(object sender, ConsoleCancelEventArgs consoleCancelEventArgs)
        {
            cancellationTokenSource.Cancel();
        }
        Console.CancelKeyPress += Foo;
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Unsubscribing...");
        Console.CancelKeyPress -= Foo;
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}

But now it hangs on Unsubscribing stroke...

Any idea why it's happening? I want to run some background task and wait until it finished in console app, but for described reasons my app is just broken.


回答1:


The issue is not your cancellation token, it's the fact that you chose to test with CancelKeyPress. When this event happens, you get given the ConsoleCancelEventArgs, which has a Cancel property:

Gets or sets a value that indicates whether simultaneously pressing the Control modifier key and the C console key (Ctrl+C) or the Ctrl+Break keys terminates the current process. The default is false, which terminates the current process.

Since you're not setting it to true, your application terminates after the event handler has finished running. Depending on exactly what's going on at the time, it seems that sometimes the cancellation token has time to break out of the while loop, other times it doesn't:

test runs

Your original code can be fixed as follows:

public static void Main()
{
    using (var cancellationTokenSource = new CancellationTokenSource())
    {
        Console.CancelKeyPress += (_, ccea) => {
            cancellationTokenSource.Cancel();
            ccea.Cancel = true; //cancel the cancel.  There's too many cancels!
        };
        while (!cancellationTokenSource.Token.WaitHandle.WaitOne(1000))
        {
            Console.WriteLine("Still running...");
        }
        Console.WriteLine("Cancellation is requested. Trying to dispose cancellation token...");
    }
    Console.WriteLine("Just before close");
}


来源:https://stackoverflow.com/questions/49537037/why-cancellationtokensource-hangs-an-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!