Delphi定时器线程

时间:2021-08-19 03:58:31

UntMyTaskTimer.pas

//任务定时器--APC函数(异步过程调用)
//由于在调用APC函数时,SleepEx会锁死当前线程
//所以,需要创建单独的线程来处理


unit UntMyTaskTimer;

interface

uses
Windows, Messages, SysUtils, Variants, Classes;

type

TTimerAPCProc = procedure(
lpArgToCompletionRoutine: Pointer;
dwTimerLowValue: DWORD;
dwTimerHighValue: DWORD
); stdcall;

TTimerThread = class(TThread)
private
thTimer: Cardinal;
FDueTime: Int64; //首次执行时间,单位:100纳秒

//起始时间(第二个参数)有三种赋值方法:
//1、> 0 时是绝对时间, 是一个 TFileTime 格式的时间(具体赋值方法后面详解);
//2、< 0 时是相对时间, 相对是相对于当前, 譬如 -50000000 表示 5 秒钟后执行(单位是0.1毫秒, 后面详述);
//3、= 0 时, 立即执行, 不再等待;


FPeriod: Longint; //执行周期,单位:毫秒

//间隔时间(第三个参数)有两种情况:
//1、譬如 5000 表示每隔 5 秒钟执行一次, 其单位是毫秒; 本页第二个例子使用了 500(半秒);
//2、如果赋值为 0, 表示根据起始时间只执行一次, 不再重复执行.


FTimes: Integer; //执行次数

FTimerAPCProc: TTimerAPCProc;

FP: Pointer; //FTimerAPCProc的第一个参数
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;

property DueTime: Int64 read FDueTime write FDueTime;
property Period: Longint read FPeriod write FPeriod;
property Times: Longint read FTimes write FTimes;
property TimerAPCProc: TTimerAPCProc read FTimerAPCProc write FTimerAPCProc;
property P: Pointer read FP write FP;
end;

const
F1MILLISECOND = 10000; //1毫秒内含10000个100纳秒

implementation


{ TTimerThread }

constructor TTimerThread.Create(CreateSuspended: Boolean);
begin
thTimer:= CreateWaitableTimer(nil,False,nil);
FDueTime:= 0;
FPeriod:= 0;
FTimes:= 0;
inherited Create(true);
FreeOnTerminate:= True;
end;

destructor TTimerThread.Destroy;
begin
CloseHandle(thTimer);
inherited;
end;

procedure TTimerThread.Execute;
var
i: Integer;
begin
inherited;
SetWaitableTimer(thTimer,FDueTime,FPeriod,@FTimerAPCProc,FP,False);

if FTimes=0 then
SleepEx(INFINITE, True)
else
begin
for i:= 0 to FTimes-1 do
SleepEx(INFINITE, True);
end;
end;

end.


引用方式:

var
p: TPoint;

procedure TimerAPCProc2(lpArgToCompletionRoutine: Pointer; dwTimerLowValue: DWORD;
dwTimerHighValue: DWORD); stdcall;
var
p:TPoint;
begin
P:= PPoint(lpArgToCompletionRoutine)^;
Form1.Canvas.TextOut(p.X,p.Y,FormatDateTime('yyyy-MM-dd HH:mm:ss.zzz',Now));
form1.mmo1.Lines.Add('X:'+IntToStr(p.X)+';Y:'+IntToStr(p.Y));
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
t: TTimerThread;
begin
t:= TTimerThread.Create(True);
t.DueTime:= -20000000;
t.TimerAPCProc:= TimerAPCProc2;
P:= Point(X,Y);
t.P:= @p;
t.Resume;
end;
点击了窗体2秒之后,在点击的位置才会显示出当前时间。

还需要继续完善:在为APC函数传递参数时,需要将参数定义为全局变量,这样不好。应该在传递参数时从参数指针地址获取参数的值,保存到线程中。

参考文章:
多线程编程(14) - 多线程同步之 WaitableTimer (等待定时器对象)

CreateWaitableTimer和SetWaitableTimer函数(定时器)