Как работают таймеры в службе Windows, когда система спит?

Предполагая, что у меня есть служба Windows, у которой есть таймер, который запускается каждые 6 часов, я ожидаю, что он будет стрелять 4 раза в день. Скажем: 0000, 0600, 1200 1800. (Военное время, такое же, как 00:00 и т.д.)

Если система переходит в режим сна 1000 и просыпается при 1700, что происходит?

  • будет ли он снова срабатывать при 1900, потому что у него есть 2 часа на таймере?
  • он выстрелит сразу (потому что он пропустил его 1200), а затем снова выстрелил в 2300 (добавив 6 часов к текущему времени?)

Я заметил, что когда компьютер идет спать, он не запускает методы OnPause или OnContinue.

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

Ответ 1

Для моих нужд я закончил работу с службой Windows, которая проверит, должна ли и когда следующая операция должна быть перенесена, и просто установите таймер на это время.
Служба Windows обновит это время после возобновления сна.

Преимущества:

  • Не влияет на время сна/пробуждения
  • консольные приложения не запускаются планировщиком.
  • используя NLog (быстрый учебник здесь) и Growl (как использовать Growl с учебником NLog здесь) для получения уведомлений на рабочем столе
  • имеющий журнал в системе, а также

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


Как и Henrik ответил и связал, правильный ответ - номер 2.

Я написал следующее в linqpad, которое похоже на ссылку в приведенном выше ответе:

static int counter = 0;
static System.Timers.Timer my_timer;

void Main()
{
    // Set up a timer to trigger every minute.
    my_timer = new System.Timers.Timer();

    DateTime now = DateTime.Now;
    my_timer.Interval = (60 - now.Second) * 1000; // Fire at beginning of minute
    string.Format("First tick in {0} seconds", my_timer.Interval/1000).Dump();

    my_timer.Elapsed += OnTimer;
    my_timer.Start();

    while (counter < 5) {    // sleep away until 5 ticks happen
        Thread.Sleep(5000);
    }

    // stop timer and say goodbye
    my_timer.Stop();
    DateTime.Now.Dump("Finished running, shutting down");
}

// Print time and counter every timer tick
void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
    if (my_timer.Interval != 60000) // set to one minute after first time
        my_timer.Interval = 60000; 

    DateTime.Now.ToString("HH:mm:ss.fff").Dump("On Timer fired:");
    (counter++).Dump("Static counter :");
}

Получение результатов:

Сначала отметьте: 37 секунд

Включен Таймер: 08: 47: 00.552
Статический счетчик: 0

Включен Таймер: 08: 48: 00.557
Статический счетчик: 1

Включено Таймер: 08: 49: 00.571
Статический счетчик: 2

//Запустите компьютер в течение 3 минут в 08:49:30

Включен Таймер: 08: 52: 33.509
Статический счетчик: 3

Включено Таймер: 08: 53: 33,510
Статический счетчик: 4

Законченный запуск, завершение работы 1/09/2014 8:53:38 AM

Итак, очевидно, что компьютер знает, что он пропустил тик, он запускает метод один раз и продолжает оттуда. Обратите внимание, что он запускается только один раз.

Но был бы рад, если кто-то, кто знает, что происходит за кулисами, может пролить свет на это.

Ответ 2

Как уже упоминалось в комментариях: используйте диспетчер задач вместо таймеров. См. эту статью для дальнейшего обсуждения.

Вопрос о том, как работают таймеры во время сна, все же интересен. В конкретном случае, о котором вы говорите, вариант 2. будет наблюдаемым поведением. Таймер возобновит свое возобновление, потому что он пропустил событие во время сна и затем начал отсчет с 0 снова. В следующий раз, когда он срабатывает, будет в 23:00. Этот ответ содержит пример кода для поддержки наблюдения.

Если вы хотите обнаружить, когда система спит и возобновляется, подпишитесь на SystemEvents.PowerModeChanged. Это событие PowerModeChangedEventArgs содержит Mode, которого вас интересуют Suspend и Resume.