Таймер С# срабатывает до их интервала времени

У нас возникает следующая проблема при использовании System.Threading.Timer (.NET 2.0) из службы Windows.

  • Существует около 12 различных объектов таймера.
  • У каждого таймера есть время и интервал. Это верно.
  • Наблюдается, что через 3-4 часа таймеры начинают сигнализацию до истечения интервала. Например, если таймер должен сигнализировать в 4:59:59, он получает сигнал в 4:59:52, 7 секунд раньше.

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

Спасибо, Свати

Ответ 1

Отличный вопрос... и вот причина:

"Сроки" - это сложная вещь, когда дело доходит до компьютеров... вы никогда не сможете полагаться на "интервал", чтобы быть идеальным. Некоторые компьютеры будут "галопировать" таймер только каждые 14-15 миллисекунд, причем несколько чаще, чем несколько раз.

Итак:

Thread.Sleep(1);

Может потребоваться от 1 до 30 миллисекунд для запуска.

Вместо этого, если вам нужен более точный таймер, вам нужно записать DateTime, когда вы начнете, а затем в таймеры вам придется проверять, вычитая DateTime.Now и ваше исходное время, чтобы узнать, является ли это "временем" для запуска "вашего кода.

Вот пример кода, который вам нужно сделать:

DateTime startDate = DateTime.Now;

Затем запустите свой таймер с интервалом, установленным на 1 миллисекунду. Затем в вашем методе:

if (DateTime.Now.Subtract(startDate).TotalSeconds % 3 == 0)
{
    // This code will fire every 3 seconds.
}

Этот код выше будет стрелять верно каждые 3 секунды. Вы можете оставить его работать в течение 10 лет, и он будет срабатывать каждые 3 секунды.

Ответ 2

Объяснение Тимоти убедительно, но System.Threading.Timer уже работает таким образом. По крайней мере, в реализации Rotor он использует значение, возвращаемое GetTickCount(), чтобы вычислить, когда произойдет следующий обратный вызов. Не очень вероятно, что реальная CLR тоже это сделает, более вероятно использование CreateTimerQueueTimer(). Тем не менее, эта функция API также, вероятно, будет зависеть от внутреннего тика, увеличенного прерыванием тактового сигнала.

Проблема заключается в том, насколько хорошо внутренний таймер (возвращаемый GetTickCount() и Environment.TickCount) синхронизируется с абсолютным временем стены (как возвращается DateTime.Now). К сожалению, эта деталь реализации HAL на вашем аппарате - уровень абстракции оборудования. Конструктор машин может предоставить пользовательский HAL, который был настроен для работы с BIOS и чипсетом.

Я бы ожидал проблем, если машина имеет два источника синхронизации, микросхему часов, которая была предназначена для отслеживания времени на стене и продолжает тикать даже вы отключите питание компьютера, а другая частота доступна на чипсете, который можно разделить, чтобы обеспечить прерывание часов. Оригинальный IBM AT PC работал именно так. Часовому чипу обычно можно доверять, часы были бы сильно отключены, если это неточно. Чипсет не может, резкие углы по качеству осцилляторов - это простой способ спасти копейки.

Решите свою проблему, избегая длительных периодов на вашем таймере и пересчитывая следующее время от DateTime. Теперь в обратном вызове.

Ответ 3

Возможно, перепланирование выполняется после выполнения операции, которая занимает несколько секунд. Или вы не контролируете это?

Ответ 4

Это не может быть управление, поскольку оно зависит от скорости системы, если у вас суперкомпьютер, тогда может быть недостаточно разницы, но если у вас нормальный ПК, тогда будет разница в таймерном интервале после длительного выполнения.

Надеюсь, что это поможет.