Есть ли таймер задержки, когда система работает?

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

А) Настройка ожидаемого таймера (проверка ошибок не производится):

HANDLE hWTimer = ::CreateWaitableTimer(NULL, FALSE, NULL);

//As an example, set timer to wait for 40 minutes
int nWaitMins = 40;

LARGE_INTEGER li;
ULONGLONG uiWaitMs = (ULONGLONG)nWaitMins * 60LL * 1000LL;
li.QuadPart = -10000LL * uiWaitMs;  //Convert to 100 nanosecond intervals (must be negative for relative time)
::SetWaitableTimer(hWTimer, &li, 0, NULL, NULL, FALSE);     //Don't wake the system

Б) В ожидании этого (из рабочего потока):

//Wait for timer to fire
::WaitForSingleObject(hWTimer, INFINITE);

Это действительно хорошо работает с одним предупреждением (если система не переведена в спящий режим или находится в спящем режиме). В этом случае, что происходит, лучше всего показано на этой диаграмме:

когда мне нужно сделать следующее:

Есть ли таймер, чтобы делать то, что я хочу здесь?

PS. Копии моего сервиса отправляют отчеты на наш веб-сервер с нескольких рабочих станций. Используя вышеописанную технику, я пытаюсь рандомизировать время отправки для облегчения работы сервера. Поскольку все рабочие станции находятся в спящем режиме, а затем просыпаются примерно одновременно, моя техника "рандомизации" не работает, когда машины выходят из спящего режима.

PS2. Мне нужно указать, что это нужно для работы под Windows XP.

3 ответа

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

Когда вы получите WM_POWERBROADCAST с PBT_ABTSUSPEND, остановите свой таймер и отследите, сколько времени у вас осталось. Когда PBT_ABTRESUMESUSPEND событие получено, запустите таймер снова с оставшимся временем.

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

Чтобы все рабочие станции не отправляли отчеты одновременно, вы просто устанавливаете случайный период ожидания в своей программе отчетов, подождите 0-20 минут в случайном порядке, прежде чем отправлять отчет. Таким образом, даже если вы запланируете все задания на каждой рабочей станции в одном и том же расписании, отчеты не будут отправляться вместе.

Запланированные задачи также могут разбудить ваши рабочие станции для отправки отчетов.

Обновлено.

Если вы хотите ждать, основываясь на времени настенных часов (фактическом реальном времени, не зависящем от системного режима сна / гибернации), вы хотите использовать функции пула потоков Win32, такие как CreateThreadPoolTimer или CreateThreadpoolWait.

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

Кроме того, что бы это ни стоило, условная переменная C++ в Win32 имеет метод wait_until, но на самом деле он реализован с системным временем.

Наконец, многие API имеют возможность "ложного пробуждения" или слишком раннего пробуждения. Это зависит от вашего кода, чтобы решить, были ли выполнены условия. Если вам нужно быть точным, лучше всего следить за временем до и после завершения обратного вызова таймера. Затем измерьте разницу. Для системного времени используйте GetTickCount64 или GetTickCount. Для настенных часов используйте (по иронии судьбы) API под названием GetSystemTime. Если вы обнаружите, что проснулись слишком рано, просто запланируйте таймер, чтобы снова подождать нужное время.

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