捕获取消事件后程序未完成



为什么按 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(但这些都不是问题的根源)。

相关内容

  • 没有找到相关文章

最新更新