Тема не просыпается от Thread.Sleep () - PullRequest
5 голосов
/ 27 августа 2008

У нас есть служба 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 через пару раз, когда база данных исчезла, и мы вернулись к файлам журналов 3Gb, полным ошибок подключения к базе данных.

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

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

Ответы [ 8 ]

5 голосов
/ 27 августа 2008

Закопаться и узнать? Прикрепи отладчика к этому ублюдку!

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

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

А может быть, но почти наверняка нет, следующее:

  • Сон () зависает.

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

3 голосов
/ 27 августа 2008

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

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

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

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

2 голосов
/ 05 июля 2010

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

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

Прерывание потоков не работает в контексте обработчика исключений.

0 голосов
/ 14 февраля 2009

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

0 голосов
/ 22 сентября 2008

Я так и не понял, что происходит, но, похоже, это связано с тем, что 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, поэтому все непредвиденные события будут регистрироваться. Я обновлю этот ответ, если когда-нибудь узнаю больше.

0 голосов
/ 27 августа 2008

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

0 голосов
/ 27 августа 2008

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

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

0 голосов
/ 27 августа 2008

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

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