为什么按 Ctrl+C 时此控制台应用不退出?
程序输出:
Press Ctrl+C to stop...
doing stuff.
doing stuff.
...
*Ctrl+C pressed*
exiting...
*never actually exits*
class Program {
static void Main(string[] args) {
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args) {
MyAsyncClass myAsync = new MyAsyncClass();
var tcs = new TaskCompletionSource<object>();
Console.CancelKeyPress += (sender, e) => { tcs.SetResult(null); };
var task = Task.Run(() => myAsync.Start());
await Console.Out.WriteLineAsync("Press Ctrl+C to stop...");
await tcs.Task;
await Console.Out.WriteLineAsync("exiting...");
}
}
public class MyAsyncClass {
public async Task Start() {
while(true) {
await Console.Out.WriteLineAsync("doing stuff.");
Thread.Sleep(1000);
}
}
}
将ConsoleCancelEventArgs.Cancel
属性设置为 true
:
Console.CancelKeyPress += (sender, e) =>
{
tcs.SetResult(null);
e.Cancel = true; // <-------- add this to your code
};
这将允许代码继续到程序结束并正常退出,而不是在事件处理程序完成后尝试终止应用程序的Ctrl+C
。
请注意,在测试中,我发现这似乎仅在附加Visual Studio调试器(与F5
一起运行)时才重要。 但是在没有附加一个的情况下运行(Ctrl+F5
,或者只是运行编译.exe)似乎并不关心是否设置了此属性。 我找不到任何解释为什么会这样的信息,但我的猜测是存在某种竞争条件。
最后,将CancellationToken
传递到您的myAsync.Start
方法中并使用它而不是while(true)
是一种很好的形式。 最好使用 await Task.Delay
而不是 Thread.Sleep
(但这些都不是问题的根源)。