Поток не просыпается из Thread.Sleep ()

У нас есть служба Windows, написанная на C#. Сервис порождает поток, который делает следующее:

private void ThreadWorkerFunction()
{
  while(false == _stop) // stop flag set by other thread
  {
    try
    {
      openConnection();

      doStuff();

      closeConnection();
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      Thread.Sleep(TimeSpan.FromMinutes(10));
    }
  }
}

Мы добавили Thread.Sleep через пару раз, когда база данных исчезла, и мы вернулись к файлам журналов 3 Гбайт, заполненным ошибками подключения к базе данных.

Это работало нормально в течение нескольких месяцев, но недавно мы видели несколько случаев, когда оператор log.Error () регистрирует исключение «System.InvalidOperationException: этот SqlTransaction завершен; он больше не может использоваться», а затем никогда не возвращается . Службу можно оставить работающей на несколько дней, но больше ничего не будет регистрироваться.

Прочитав немного, я знаю, что Thread.Sleep не идеален, но почему он просто никогда не вернется?

Поток не просыпается из Thread.Sleep (); Maybe it just didn't get enough sleep? :P
anon271334 07.02.2011 14:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
4 165
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Вы пробовали использовать Монитор. Импульс (убедитесь, что ваш поток использует управление потоками, прежде чем запускать это), чтобы заставить поток что-то делать? Если это сработает, вам придется немного подробнее изучить логику потоковой передачи.

We put the Thread.Sleep in after a couple of times when the database had gone away and we came back to 3Gb logs files full of database connection errors.

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

Предположим, я написал стандартную заметку о том, как вы должны открывать свое соединение в последний возможный момент и закрывать его при первой же возможности, вместо того, чтобы охватывать потенциально огромную функцию так, как вы это сделали (но, возможно, это артефакт. вашего демонстрационного кода, и ваше приложение действительно написано правильно).

Когда вы говорите, что он сообщает об ошибке, которую вы описываете, вы имеете в виду, что этот обработчик сообщает об ошибке? Причина, по которой мне это непонятно, заключается в том, что во фрагменте кода вы говорите «Что-то пошло не так», но вы не сказали этого в своем описании; Я бы не хотел, чтобы это было чем-то настолько глупым, поскольку исключение перехватывается где-то еще, а код застревает где-то, кроме сна.

Ответ принят как подходящий

Копайся и узнаешь? Воткни этому ублюдку отладчик!

Я вижу по крайней мере следующие возможности:

  1. зависает система логирования;
  2. поток завершился нормально, но служба все еще работает, потому что в какой-то другой части есть логическая ошибка.

И, возможно, но почти наверняка нет, следующее:

  • Sleep () зависает.

Но в любом случае присоединение отладчика покажет вам, существует ли еще поток и действительно ли он завис.

Из опубликованного вами кода неясно, что после создания исключения система определенно может перезапуститься - например, если исключение исходит от doStuff (), тогда поток управления вернется (после 10-минутного ожидания) к openConnection (), никогда не проходя через closeConnection ().

Но, как говорили другие, просто подключите отладчик и найдите, где он на самом деле.

Попробуйте Thread.Sleep (10 * 60 * 1000)

Я так и не понял, что происходит, но, похоже, это было связано с исключениями ThreadInterruptedExceptions, которые были выброшены во время 10-минутного сна, поэтому я изменил код на:

private void ThreadWorkerFunction()
{
  DateTime? timeout = null;

  while (!_stop)
  {
    try
    {
      if (timeout == null || timeout < DateTime.Now)
      {
        openDatabaseConnections();

        doStuff();

        closeDatabaseConnections();
      }
      else
      {
        Thread.Sleep(1000);
      }
    }
    catch (ThreadInterruptedException tiex)
    {
      log.Error("The worker thread was interrupted... ignoring.", tiex);
    }
    catch (Exception ex)
    {
      log.Error("Something went wrong.", ex);

      timeout = DateTime.Now + TimeSpan.FromMinutes(10);
    }
  }
}

Помимо конкретного перехвата ThreadInterruptedException, это просто кажется более безопасным, поскольку весь сон происходит в блоке try, поэтому все неожиданные события будут регистрироваться. Я обновлю этот ответ, если когда-нибудь узнаю больше.

Находится ли ваш рабочий поток в пуле потоков или это настоящий поток?

Roger Lipscombe 10.11.2008 23:16

Наткнулся на это, когда искал собственную проблему Thread.Sleep. Это может быть связано или нет, но если ваш doSomething () выдает исключение, closeDatabaseConnections () не произойдет, что может привести к утечке ресурсов ... Я бы поместил это в блок finally. Просто кое что для раздумий.

У меня была точно такая же проблема. Перемещение строки сна за пределы обработчика исключений устранило проблему для меня, например:

bool hadError = false;
try {
  ...
} catch (...) {
  hadError = true;
}
if (hadError)
  Thread.Sleep(...);

Кажется, что прерывание потоков не работает в контексте обработчика исключений.

Другие вопросы по теме