为何CancellationTokenSource会导致应用程序挂起?
Ah, I see exactly what's causing the hang here! Let's break this down step by step, then fix it.
Why Your App Is Hanging
The core problem is missing one critical line in your Console.CancelKeyPress event handler: you're not telling the CLR to stop auto-terminating the process after handling the Ctrl+C signal. Here's the play-by-play when you press Ctrl+C:
- The OS sends a SIGINT signal to your app, and .NET spins up a dedicated signal-handling thread to run your lambda (
cancellationTokenSource.Cancel()). - Calling
Cancel()flips the CancellationToken's WaitHandle to a signaled state, so your main thread's loop exits immediately. - Your main thread moves on to clean up: it prints the cancellation message, then hits the end of the
usingblock, which callsCancellationTokenSource.Dispose(). - Meanwhile, once your event handler lambda finishes, the CLR tries to automatically terminate the process with
Environment.Exit()—but your main thread is right in the middle of disposing the CancellationTokenSource. - This creates a deadlock: the process termination waits for the main thread to finish its work, but the disposal operation gets stuck waiting on internal resources that are tied up by the termination flow. The result? Your app hangs forever, never reaching that final "Just before close" line.
The Fix
All you need to do is add e.Cancel = true to your event handler. This tells the CLR "I've got this—don't kill the process automatically; let me clean up properly first."
Here's the corrected code:
public static void Main() { using (var cancellationTokenSource = new CancellationTokenSource()) { Console.CancelKeyPress += (_, e) => { e.Cancel = true; // This is the magic line! 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"); }
What Happens Now
When you press Ctrl+C:
- The event handler stops the CLR from auto-terminating the process
Cancel()triggers the main thread to exit its loop- The main thread safely disposes the CancellationTokenSource without any deadlock
- Your app prints the final line and exits cleanly
If you didn't care about clean cleanup, you could just call Environment.Exit() directly in the event handler—but skipping disposal is risky if you're using resources that need explicit cleanup (like file handles or network connections).
内容的提问来源于stack exchange,提问作者Alex Zhukovskiy

