Содержание материала

 

Waitable timer (таймер ожидания)

Таймер ожидания отсутствует в Windows 95 и для его использования необходима Windows 98 или Windows NT 4.0 и выше.

Таймер ожидания переходит в сигнальное состояние по завершении заданного интервала времени. Для его создания используется функция:

function CreateWaitableTimer(

lpTimerAttributes: PSecurityAttributes;     // Адрес структуры

                                             // TSecurityAttributes

bManualReset: BOOL;  // Задает, будет ли таймер переходить в

                      // сигнальное состояние по завершении функции

                      // ожидания

lpTimerName: PChar   // Имя объекта

): THandle; stdcall;

 

Если параметр bManualReset равен TRUE, то таймер после срабатывания функции ожидания остается в сигнальном состоянии до явного вызова SetWaitableTimer, если FALSE - таймер автоматически переходит в несигнальное состояние.

Если lpTimerName совпадает с именем уже существующего в системе таймера функция возвращает его идентификатор, позволяя использовать объект для синхронизации между процессами. Имя таймера не должно совпадать с именем уже существующих объектов типов event, semaphore, mutex, job или file-mapping.

Идентификатор уже существующего таймера можно получить функцией:

 

function OpenWaitableTimer(

dwDesiredAccess: DWORD;  // Задает права доступа к объекту

bInheritHandle: BOOL;    // Задает, может ли объект наследоваться

                          // дочерними процессами

lpTimerName: PChar       // Имя объекта

): THandle; stdcall;

 

Параметр dwDesiredAccess может принимать следующие значения:

TIMER_ALL_ACCESS        Разрешает полный доступ к объекту        

TIMER_MODIFY_STATE        Разрешает изменять состояние таймера функциями SetWaitableTimer и CancelWaitableTimer        

SYNCHRONIZE        Только Windows NT разрешает использовать таймер в функциях ожидания        

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

 

function SetWaitableTimer(

hTimer: THandle;                  // Идентификатор таймера

const lpDueTime: TLargeInteger;   // Время срабатывания

lPeriod: Longint;                 // Период повторения срабатывания

pfnCompletionRoutine: TFNTimerAPCRoutine;  // Процедура-обработчик

lpArgToCompletionRoutine: Pointer;// Параметр процедуры-обработчика

fResume: BOOL                     // Задает, будет ли операционная

                                   // система «пробуждаться»

): BOOL; stdcall;

 

Рассмотрим параметры подробнее.

lpDueTime

Задает время срабатывания таймера. Время задается в формате TFileTime и базируется на coordinated universal time (UTC), т.е. должно указываться по Гринвичу. Для преобразования системного времени в TFileTime используется функция SystemTimeToFileTime. Если время имеет положительный знак, оно трактуется как абсолютное, если отрицательный как относительное от момента запуска таймера.

lPeriod

Задает срок между повторными срабатываниями таймера. Если lPeriod равен 0 таймер сработает один раз.

pfnCompletionRoutine

Адрес функции, объявленной как:

 

procedure TimerAPCProc(

lpArgToCompletionRoutine: Pointer;  // данные

dwTimerLowValue: DWORD;   // младшие 32 разряда значения таймера

dwTimerHighValue: DWORD;  // старшие 32 разряда значения таймера

); stdcall;

 

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

lpArgToCompletionRoutine значение, переданное в качестве одноименного параметра в функцию SetWaitableTimer. Приложение может использовать его для передачи в процедуру обработки адреса блока данных, необходимых для её работы
dwTimerLowValue и dwTimerHighValue соответственно члены dwLowDateTime и dwHighDateTime структуры TFileTime. Они описывают время срабатывания таймера. Время задается в UTC формате (по Гринвичу).

Если дополнительная функция обработки не нужна, в качестве этого параметра можно передать NIL.

lpArgToCompletionRoutine

Это значение передается в функцию pfnCompletionRoutine при её вызове.

fResume

Определяет необходимость "пробуждения" системы, если на момент срабатывания таймера она находится в режиме экономии электроэнергии (suspended). Если операционная система не поддерживает пробуждение и fResume равно TRUE, функция SetWaitableTimer выполнится успешно, однако последующий вызов GetLastError вернет результат ERROR_NOT_SUPPORTED.

 

Если необходимо перевести таймер в неактивное состояние, это можно сделать функцией:

function CancelWaitableTimer(hTimer: THandle): BOOL; stdcall;

Эта функция не изменяет состояния таймера и не приводит к срабатыванию функций ожидания и вызову процедур-обработчиков.

По завершении работы объект должен быть уничтожен функцией CloseHandle

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

Code:

unit WaitThread;

 

interface

 

uses Classes, Windows;

 

type

TWaitThread = class(TThread)

   WaitUntil: TDateTime;

   procedure Execute; override;

end;

 

implementation

 

uses SysUtils;

 

procedure TWaitThread.Execute;

var

Timer: THandle;

SystemTime: TSystemTime;

FileTime, LocalFileTime: TFileTime;

begin

Timer := CreateWaitableTimer(NIL, FALSE, NIL);

try

   DateTimeToSystemTime(WaitUntil, SystemTime);

   SystemTimeToFileTime(SystemTime, LocalFileTime);

   LocalFileTimeToFileTime(LocalFileTime, FileTime);

   SetWaitableTimer(Timer, TLargeInteger(FileTime), 0,

     NIL, NIL, FALSE);

   WaitForSingleObject(Timer, INFINITE);

finally

   CloseHandle(Timer);

end;

end;

 

end.

Использовать этот класс можно, например, следующим образом:

type

TForm1 = class(TForm)

   Button1: TButton;

   procedure Button1Click(Sender: TObject);

private

   procedure TimerFired(Sender: TObject);

end;

 

...

 

 

implementation

 

uses WaitThread;

 

procedure TForm1.Button1Click(Sender: TObject);

var

T: TDateTime;

begin

with TWaitThread.Create(TRUE) do

begin

   OnTerminate := TimerFired;

   FreeOnTerminate := TRUE;

   // Срок ожидания закончится через 5 секунд

   WaitUntil := Now + 1 / 24 / 60 / 60 * 5;

   Resume;

end;

end;

 

procedure TForm1.TimerFired(Sender: TObject);

begin

ShowMessage('Timer fired !');

end;

 

Добавить комментарий

Не использовать не нормативную лексику.

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

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить