问题
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:
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