您的位置:首页 > 大数据 > 人工智能

定时器的使用 之 SetWaitableTimer

2009-05-26 09:32 429 查看
使用SetWaitableTimer做定时器,可以精确到100纳秒,关键是可以线程执行,简单的封装了个Delphi类,方便使用,源代码如下

]{******************************************************************************}
{ @UnitName     : uWaitableTimer.pas                                           }
{ @Project      : Waitable Timer Objects                                       }
{ @Copyright    : Budded Software Studio                                       }
{ @Author       : Budded                                                       }
{ @Description  : Description                                                  }
{ @FileVersion  : 1.0.0.0                                                      }
{ @CreateDate   : 2009-04-22                                                   }
{ @Comment      : Waitable Timer Objects                                       }
{ @LastUpdate   : Budded, 2009-04-22                                           }
{ @History      : Created By Budded, 2009-04-22 13:00                          }
{******************************************************************************}
unit uWaitableTimer;
interface
uses
SysUtils, Classes, Windows;
type
TTimerAPCProc = procedure (const Param: Pointer; const TimerLowValue, TimerHighValue: DWord); stdcall;
TWaitableTimer = class
private
FHandle: THandle;
FList: TList;
procedure QueueUserAPCInner(const Data: Pointer);
procedure FreeListMem();
public
constructor Create(const AName: String = ''; const ManualReset: Boolean = True);
destructor Destroy(); override;
function SetTimer(var lpDueTime: TLargeInteger; const lPeriod: Cardinal;
pfnCompletionRoutine: TTimerAPCProc;
lpArgToCompletionRoutine: Pointer): Boolean; overload;
function SetTimer(var lpDueTime: TLargeInteger; const lPeriod: Cardinal;
pfnCompletionRoutine: TNotifyEvent;
lpArgToCompletionRoutine: TObject): Boolean; overload;
function CancelTimer(): Boolean;
property Handle: THandle read FHandle;
end;
implementation
type
TCallbackType = (ctFarProc, ctNotifyEvent);

TAccessType = (atGet, atFree);
TWorkThread = class(TThread)
protected
procedure Execute; override;
public
class function ThreadHandle(const AccType: TAccessType = atGet): THandle;
end;

PCallbackParam = ^TCallbackParam;
TCallbackParam = packed record
Timer: THandle;
AType: TCallbackType;
lpDueTime: TLargeInteger;
lPeriod: Cardinal;
case TCallbackType of
ctFarProc: (
pfnCompletionRoutine: TTimerAPCProc;
lpArgToCompletionRoutine: Pointer;
);
ctNotifyEvent: (
pfnNotifyEnevt: TNotifyEvent;
lpSender: TObject;
);
end;
procedure Debug(const Msg: String);
var
FData: String;
begin
FData := Format('Curr: %d; Main: %d; Msg: %s', [GetCurrentThreadID, MainThreadID, Msg]);
OutputDebugString(PChar(FData));
end;
procedure TimerAPCProc(const Param: Pointer; const TimerLowValue, TimerHighValue: DWord); stdcall;
var
FData: PCallbackParam;
begin
FData := Param;
if Assigned(FData) then
try
case FData.AType of
ctFarProc:
if Assigned(FData.pfnCompletionRoutine) then
FData.pfnCompletionRoutine(FData.lpArgToCompletionRoutine, TimerLowValue, TimerHighValue);
ctNotifyEvent:
if Assigned(FData.pfnNotifyEnevt)then
FData.pfnNotifyEnevt(FData.lpSender);
end;
finally
// do not dispose FData pointer
end;
end;
procedure TimerQueueAPCProc(const Param: Pointer); stdcall;
var
FData: PCallbackParam;
lpDueTime: TLargeInteger;
FRtn: Boolean;
begin
FData := Param;
if Assigned(FData) and (FData.Timer > 0) then
begin
lpDueTime := -10000 * FData.lpDueTime;  // 纳秒级
FRtn := SetWaitableTimer(FData.Timer, lpDueTime, FData.lPeriod, @TimerAPCProc,
FData, False);
if not FRtn then
Debug('SetWaitableTimer ' + IntToStr(GetLastError));
end;
end;
{ TWaitableTimer }
function TWaitableTimer.CancelTimer: Boolean;
begin
Result := CancelWaitableTimer(FHandle)
end;
constructor TWaitableTimer.Create(const AName: String;
const ManualReset: Boolean);
begin
inherited Create();
FList := TList.Create;
FHandle := CreateWaitableTimer(nil, ManualReset, PChar(AName));
end;
destructor TWaitableTimer.Destroy;
begin
CancelTimer;
CloseHandle(FHandle);
FreeListMem();
if Assigned(FList) then
FreeAndNil(FList);

inherited;
end;
procedure TWaitableTimer.FreeListMem;
var
I: Integer;
begin
if Assigned(FList) then
for I := 0 to FList.Count - 1 do
Dispose(FList[I]);
end;
procedure TWaitableTimer.QueueUserAPCInner(const Data: Pointer);
begin
QueueUserAPC(@TimerQueueAPCProc, TWorkThread.ThreadHandle(), Cardinal(Data));
end;
function TWaitableTimer.SetTimer(var lpDueTime: TLargeInteger;
const lPeriod: Cardinal; pfnCompletionRoutine: TTimerAPCProc;
lpArgToCompletionRoutine: Pointer): Boolean;
var
FData: PCallbackParam;
begin
New(FData);
ZeroMemory(FData, SizeOf(TCallbackParam));
FData.Timer := Handle;
FData.AType := ctFarProc;
FData.lpDueTime := lpDueTime;
FData.lPeriod := lPeriod;
FData.pfnCompletionRoutine := pfnCompletionRoutine;
FData.lpArgToCompletionRoutine := lpArgToCompletionRoutine;
QueueUserAPCInner(FData);
FList.Add(FData);
end;
function TWaitableTimer.SetTimer(var lpDueTime: TLargeInteger;
const lPeriod: Cardinal; pfnCompletionRoutine: TNotifyEvent;
lpArgToCompletionRoutine: TObject): Boolean;
var
FData: PCallbackParam;
begin
New(FData);
ZeroMemory(FData, SizeOf(TCallbackParam));
FData.Timer := Handle;
FData.AType := ctNotifyEvent;
FData.lpDueTime := lpDueTime;
FData.lPeriod := lPeriod;
FData.pfnNotifyEnevt := pfnCompletionRoutine;
FData.lpSender := lpArgToCompletionRoutine;
QueueUserAPCInner(FData);
FList.Add(FData);
end;
{ TWorkThread }
procedure TWorkThread.Execute;
begin
while not Terminated do
SleepEx(INFINITE, True);
end;
class function TWorkThread.ThreadHandle(
const AccType: TAccessType): THandle;
{$J+}
const FHandle: THandle = 0;
{$J-}
begin
Result := 0;
case AccType of
atGet:
begin
if FHandle = 0 then
FHandle := TWorkThread.Create(False).Handle;
Result := FHandle;
end;
atFree:
begin
TerminateThread(FHandle, 0);
FHandle := 0;
end;
end;
end;
initialization
//  TWorkThread.ThreadHandle();
finalization
TWorkThread.ThreadHandle(atFree);

end.


使用实例如下:

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, uWaitableTimer, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ListBox1: TListBox;
Button3: TButton;
Button4: TButton;
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
FTimer: TWaitableTimer;
procedure SetTimerAPC(const Inner: Boolean = True);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TimerAPCProc(const Param: Pointer; const TimerLowValue, TimerHighValue: DWord); stdcall;
var
FData: String;
FTime: Int64;
begin
QueryPerformanceCounter(FTime);
FData := Format('Curr: %d; Main: %d; Low: %d; High: %d; Time: %d',
[GetCurrentThreadID, MainThreadID, TimerLowValue, TimerHighValue, FTime]);
if Assigned(Param) then
TListBox(Param).Items.Add(FData);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetTimerAPC(False);
end;
procedure TForm1.ListBox1Click(Sender: TObject);
var
FData: String;
begin
FData := Format('Curr: %d; Main: %d; Time: %d', [GetCurrentThreadID, MainThreadID, GetTickCount]);
if Assigned(Sender) then
TListBox(Sender).Items.Add(FData);
end;
procedure TForm1.SetTimerAPC(const Inner: Boolean);
var
FTime: TLargeInteger;
FPerid: Cardinal;
begin
FPerid := 1 * 10;
FTime := 1 * FPerid;
FTimer.SetTimer(FTime, FPerid, TimerAPCProc, ListBox1);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
FTimer.CancelTimer;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
FTimer := TWaitableTimer.Create();
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
FTimer.Free;
end;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: