【问题标题】:Program not finishing after trapping Cancel event捕获 Cancel 事件后程序未完成
【发布时间】:2019-06-19 15:00:11
【问题描述】:

为什么按下 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);
        }
    }
}

【问题讨论】:

标签: c# event-handling task cancellation


【解决方案1】:

您需要将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 也会更好(但这些都不是问题的根源)。

【讨论】:

  • 反对者 - 请解释。这确实解决了复制问题和 OP 原始问题的问题。
  • 正是我遇到和推断的。太糟糕了,在它可以节省我一些时间之前我没有找到你的答案。此外,它不仅在没有调试的情况下运行,还使用 ​​Windows cmd,在没有完成的情况下终止(不优雅),这让我认为我在取消事件中遗漏了一些东西。无论如何,我要投票,这样其他人也会看到它,我会尝试编辑问题。
猜你喜欢
  • 2013-12-10
  • 1970-01-01
  • 2015-11-30
  • 2011-03-09
  • 2020-03-11
  • 2017-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多