Таймер C # срабатывает раньше времени их интервала - PullRequest
12 голосов
/ 12 марта 2010

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

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

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

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

Ответы [ 4 ]

10 голосов
/ 12 марта 2010

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

«Время» - сложная вещь, когда дело доходит до компьютеров ... вы не можете никогда полагаться на «интервал», чтобы быть идеальным. Некоторые компьютеры «тикают» таймер только каждые 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 секунды.

7 голосов
/ 12 марта 2010

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

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

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

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

0 голосов
/ 12 марта 2010

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

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

0 голосов
/ 12 марта 2010

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

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