Thread.Sleep и Task.Delay случайным образом зависают и никогда не заканчиваются - PullRequest
0 голосов
/ 07 сентября 2018

Не дубликат. Код, приведенный ниже, также зависает и заставляет консоль ожидать ввода «случайным образом» - где-то еще большая проблема.

int i = 0;
while (true)
{
    Console.WriteLine(++i);
    System.Threading.Thread.Sleep(3000);
}

Так что у меня самая странная ошибка, и, кажется, ничто в Интернете никогда не имеет этого. Недавно я переместил свой планировщик задач на другой сервер (стандарт Windows Server 2016), и после этого приложение, кажется, случайно зависает на строке Task.Delay и никогда не запускается после нее.

Например, он просто скажет «Проверка завершена при следующем запуске в 09:31», и никогда больше не будет выполняться.

Интересно, что нажатие клавиши ввода в окне консоли запускает его выполнение, однако затем каждый раз, когда оно зависает в спящем режиме, пока приложение не закроется и не откроется заново.

Это может продолжаться много дней, не сталкиваясь с этой проблемой, а затем, по-видимому, случайно возникнет.

Я пробовал использовать Thread.Sleep вместо Task.Delay, и у обоих возникла одна и та же проблема. Я также добавил проверку, чтобы проверить, не зависла ли команда Directory.Exists, поэтому вместо этого сохранил каталоги в памяти.

Я понятия не имею, что может быть причиной этого - я никогда не испытывал ничего подобного раньше. Есть идеи?

Код приведен ниже - однако его невозможно будет воспроизвести, если представить его из-за странной природы ошибки

TLDR: Консольное приложение Windows Server 2016 зависает на Task.Delay (и Thread.Sleep) до тех пор, пока в окне консоли не будет нажата клавиша

        // This is the main execution loop
            while (true)
        {
            Task run = checkDirectoriesForAppsToRun();
            run.Wait();
        }

       static async Task checkDirectoriesForAppsToRun()
    {
        Console.WriteLine("Starting apps...");
        foreach (string subFolder in listOfSubfolders)
        {
            if (directoryExists.ContainsKey(currentDirectory + @"\" + subFolder) || System.IO.Directory.Exists(currentDirectory + @"\" + subFolder)) // Only if the sub directory exists!
            {
                if (directoryExists.ContainsKey(currentDirectory + @"\" + subFolder) == false)
                    directoryExists.Add(currentDirectory + @"\" + subFolder, true);
                foreach (string directory in System.IO.Directory.GetDirectories(currentDirectory + @"\" + subFolder))
                {
                    CheckDirectoryForApp(directory); // Load the apps xml file, and check if we need to run it.
                }
            }
            else
            {
                Console.WriteLine(subFolder + " Doesn't exist in the root directory - Please check");
            }
        }
        Console.WriteLine("Check completed next run at " + DateTime.Now.Add(timeToPause).ToShortTimeString());
        await Task.Delay(timeToPause);
    }

Ответы [ 2 ]

0 голосов
/ 10 декабря 2018

Так что, похоже, это проблема с подключением RDP, замораживающим приложения .NET во время выполнения.

Не было проблемой на Windows Server 2008 - это проблема в более поздних версиях Windows Server. Смотрите ссылку ниже. В настоящее время не удалось решить - избавился от RDP в пользу VNC, чтобы обойти проблему

https://social.msdn.microsoft.com/Forums/vstudio/en-US/f1d6d2e3-417f-4bc4-be83-1e659852d6cb/application-hang-when-using-remote-desktop?forum=vcgeneral

0 голосов
/ 07 сентября 2018

Почему бы не использовать System.Threading.Timer вместо создания собственной версии, которая представляет собой цикл? Вот для чего они были созданы. Посмотрите уже превосходные комментарии по вопросу о том, почему отправленный код может / может быть заблокирован, это легко сделать, если вы смешиваете синхронные вызовы с async/await, и также нет необходимости использовать async/await, поскольку вы используете только это для Task.Delay

private static System.Threading.Timer _timer;

static void Main(string[] args)
{
  // start the timer
  _timer = new System.Threading.Timer(checkDirectoriesForAppsToRun, null, 0, timeToPause);
}

static void StopTimer()
{
  // call this method when you want to stop the timer
  _timer?.Dispose();
}


static void checkDirectoriesForAppsToRun(object state)
{
  Console.WriteLine("Starting apps...");
  /* exising code not considered in this answer... */
  Console.WriteLine("Check completed next run at " + DateTime.Now.Add(timeToPause).ToShortTimeString());

  // await Task.Delay(timeToPause); // removed
}
...