代码之家  ›  专栏  ›  技术社区  ›  bwoogie

为什么这个任务没有完成?

c#
  •  1
  • bwoogie  · 技术社区  · 5 年前

    为什么按下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);
            }
        }
    }
    
    1 回复  |  直到 5 年前
        1
  •  -1
  •   Matt Johnson-Pint    5 年前

    你需要设置 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 (但这两者都不是问题的根源)。