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

 

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;

 

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

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

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

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


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