Почему добавление отладчика блока обработчика Console.CancelKeyPress CTRL + C завершается при выполнении задачи - PullRequest
1 голос
/ 06 февраля 2020

Мне удалось свести это к минимальному тестовому сценарию, работающему в 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...");
    }

Если я запускаю это в отладчике с Console.CancelKeyPress закомментированным, CTRL + C принудительно завершает приложение. С написанным кодом, он выводит «EXITING ...», а затем зависает, хотя мой обработчик событий ничего не делает для предотвращения завершения.

Если я запускаю из командной строки, обе версии завершаются, как и ожидалось.

Мне потребовалось некоторое время, чтобы выяснить, что незаконченное Task вовлечено, но я понятия не имею, почему обработчик событий меняет поведение. Кто-нибудь может понять, почему? Это какая-то особенность отладчика? Я не вижу ошибок в отладчике ...

Ответы [ 2 ]

0 голосов
/ 12 февраля 2020

Это проблема отладчика Visual Studio, и я думаю, что это происходит потому, что Visual Studio отслеживает все запущенные потоки отдельно и, как вы сказали, у вас есть незавершенная задача, запущенная в другом потоке.

когда вы завершаете свою программу из командной строки, используя CTRL+C, команда Line заставляет ваш основной поток остановиться. таким образом, ваш дочерний поток тоже будет останавливаться, но когда вы запускаете приложение с помощью VS-debugger, основной поток присоединяется к отладчику.

по умолчанию отладчик освободит все блокирующие потоки, если вы не обрабатываете событие Console.CancelKeyPress, но не тогда, когда вы хотите вручную завершить вызовы. ( Я не уверен, почему )

, если вы хотите заставить отладчик завершить все потоки, которые вы должны сделать это вручную.

    private static void End()
    {
      Console.WriteLine("EXITING...");
      if (Debugger.IsAttached)
          Environment.Exit(1); // this is equal to using CTRL+C in the terminal
    }

также вы следует использовать токен отмены для полной отмены выполняемых задач перед завершением работы приложения.

 class Program
    {
        private static CancellationTokenSource tokenSource;
        static async Task Main(string[] args)
        {
            tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;
            Console.CancelKeyPress += (o, e) => End(); 
            await Task.Run(() => Task.Delay(100000), token);
        }

        private static void End()
        {
            Console.WriteLine("EXITING...");
            tokenSource.Cancel();
            tokenSource.Dispose();
            if (Debugger.IsAttached)
                Environment.Exit(1);
        }
    }
0 голосов
/ 06 февраля 2020

Это только дикое предположение, но вы проверили, что происходит, когда вы устанавливаете свойство Cancel для ConsoleCancelEventArgs instance e в false?

Было бы Странно, если это решит вашу проблему, это может помочь сузить проблему.

PS: Я не могу проверить это сам, так как в настоящее время я на Linux машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...