C# 为什么添加Console.CancelKeyPress处理程序会阻止调试器CTRL+;C在任务运行时退出

C# 为什么添加Console.CancelKeyPress处理程序会阻止调试器CTRL+;C在任务运行时退出,c#,visual-studio,visual-studio-debugging,C#,Visual Studio,Visual Studio Debugging,我已成功地将其简化为在VS2017中使用.Net Framework 4.6运行的最小测试用例: static void Main(string[] args) { Console.CancelKeyPress += (o, e) => End(); //some attempt to exit gracefully Task.Run(() => Task.Delay(100000)).Wait(); } privat

我已成功地将其简化为在VS2017中使用.Net Framework 4.6运行的最小测试用例:

    static void Main(string[] args)
    {
        Console.CancelKeyPress += (o, e) => End(); //some attempt to exit gracefully
        Task.Run(() => Task.Delay(100000)).Wait();
    }

    private static void End()
    {
        Console.WriteLine("EXITING...");
    }
如果我在带有
控制台的调试器中运行此命令。取消按键
注释掉,则CTRL+C force将终止应用程序。在编写代码时,它输出“EXITING…”,然后挂起,即使我的事件处理程序没有阻止终止

如果从命令行运行,两个版本都会按预期退出


我花了一些时间才弄清楚未完成的
任务
,但我不知道事件处理程序为什么要改变行为。有人知道为什么吗?这是调试器的怪癖吗?我在调试器中没有看到任何错误…

这只是一个猜测,但是您是否检查了将实例e的Cancel属性设置为false时会发生什么情况

如果这能解决你的问题,那就太奇怪了,不过这可能有助于缩小问题的范围


PS:我自己无法测试它,因为我目前在一台Linux机器上。

这只是一个猜测,但是您是否检查过当您将实例e的Cancel属性设置为false时会发生什么情况

如果这能解决你的问题,那就太奇怪了,不过这可能有助于缩小问题的范围


PS:我不能自己测试它,因为我目前在Linux机器上。

这是一个visual studio调试器问题,我认为这是因为visual studio正在单独跟踪所有正在运行的线程,正如您所说,您有一个未完成的任务正在另一个线程中运行

当您使用
CTRL+C
从命令行终止程序时,命令行将强制主线程停止。这样子线程也会停止,但当您使用VS debugger运行应用程序时,主线程会连接到调试器

默认情况下,如果您不处理
Console.CancelKeyPress
事件,则调试器将释放所有阻塞线程,但在您希望手动控制终止调用时不会释放。()

如果要强制调试器终止所有线程,则必须手动执行此操作

private static void End()
{
控制台。写入线(“退出…”);
if(Debugger.IsAttached)
Environment.Exit(1);//这等于在终端中使用CTRL+C
}
此外,您应该使用取消令牌在应用程序终止之前完全取消正在运行的任务

类程序
{
私有静态取消令牌源令牌源;
静态异步任务主(字符串[]args)
{
tokenSource=新的CancellationTokenSource();
var token=tokenSource.token;
Console.CancelKeyPress+=(o,e)=>End();
等待任务运行(()=>Task.Delay(100000),令牌);
}
私有静态void End()
{
控制台。写入线(“退出…”);
tokenSource.Cancel();
tokenSource.Dispose();
if(Debugger.IsAttached)
环境。出口(1);
}
}

这是一个visual studio调试器问题,我认为这是因为visual studio正在单独跟踪所有正在运行的线程,正如您所说,您有一个未完成的任务正在另一个线程中运行

当您使用
CTRL+C
从命令行终止程序时,命令行将强制主线程停止。这样子线程也会停止,但当您使用VS debugger运行应用程序时,主线程会连接到调试器

默认情况下,如果您不处理
Console.CancelKeyPress
事件,则调试器将释放所有阻塞线程,但在您希望手动控制终止调用时不会释放。()

如果要强制调试器终止所有线程,则必须手动执行此操作

private static void End()
{
控制台。写入线(“退出…”);
if(Debugger.IsAttached)
Environment.Exit(1);//这等于在终端中使用CTRL+C
}
此外,您应该使用取消令牌在应用程序终止之前完全取消正在运行的任务

类程序
{
私有静态取消令牌源令牌源;
静态异步任务主(字符串[]args)
{
tokenSource=新的CancellationTokenSource();
var token=tokenSource.token;
Console.CancelKeyPress+=(o,e)=>End();
等待任务运行(()=>Task.Delay(100000),令牌);
}
私有静态void End()
{
控制台。写入线(“退出…”);
tokenSource.Cancel();
tokenSource.Dispose();
if(Debugger.IsAttached)
环境。出口(1);
}
}

有人能确认吗?在线小提琴不允许您测试CTRL+Cred
Console.CancelKeyPress+=null
也会触发此行为。我怀疑简单的调用会影响此行为()根据我的搜索,我发现Console.CancelKeyPress会在按下“CTRL+C”时触发事件。那么,我不知道你为什么要注释掉代码。另外,我不明白什么是强制终止应用程序。如果你解释这两点,你将有助于解决这个问题。这是。他们并不急于修复它,对我来说这不是一个简单的问题。操作系统似乎与此有关,如果没有调试器,它也无法正常运行。他们一直在大力修补Win10控制台子系统,以更好地支持WSL,这可能是根本问题。可能需要操作系统补丁或更新,这需要时间。有人能确认吗?在线小提琴不允许您测试CTRL+Cred
Console.CancelKeyPress+=null
也会触发此行为。我怀疑简单的调用会影响此行为()根据我的搜索,我发现Console.CancelKeyPress会在按下“CTRL+C”时触发事件。