gpt4 book ai didi

delphi - 重置有信号的可等待计时器对象句柄

转载 作者:行者123 更新时间:2023-12-01 21:16:14 27 4
gpt4 key购买 nike

当我使用绝对时间和 waitformultipleobjects () 时,我遇到了一个可等待计时器对象的小问题。

一旦计时器收到信号,我需要重置对象,而我能找到的唯一方法是在未来不切实际的到期时间再次使用 setwaitabletimer 。这将使计时器在操作系统唤醒计时器中毫无理由地保持事件状态。我需要保留句柄,因为在某些情况下我需要重新激活计时器,并且我使用 waitformultipleobjects 数组中的计时器对象,因此关闭 FWaitTimer 句柄并不好。

我的理解是否正确,或者有更好的方法吗?

我的完整代码如下所示,请忽略其他 waitfor 对象,它只是 FWaitTimer 对象。

unit frmMain;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.WinXPickers, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters, dxSkinsCore,
dxSkinTheAsphaltWorld, dxSkinsDefaultPainters, cxCalendar, Vcl.ExtCtrls, cxContainer, cxEdit, dxCore, cxDateUtils, cxDropDownEdit, cxTextEdit, cxMaskEdit,
cxSpinEdit, cxTimeEdit, Vcl.Menus, Vcl.StdCtrls, cxButtons, dateutils, syncObjs, UTimer;

const
WM_WATINGDONE = WM_USER + 100;

type

TMyWaitThread = class(TThread)
private
FWaitTimer : THandle;
FTerminateEvent : TEvent;
FPeriodicTimer : TADTimer;
FWaitTime: TDateTime;
procedure SetWaitTime(const Value: TDateTime);
property WaitTime : TDateTime read FWaitTime write SetWaitTime;
public
constructor Create; overload;
constructor Create(CreateSuspended: Boolean); overload;
destructor Destroy; override;
procedure execute; override;
procedure Terminate;
end;



TForm1 = class(TForm)
cxClock1: TcxClock;
Timer1: TTimer;
cxDateEdit1: TcxDateEdit;
btnWait: TcxButton;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnWaitClick(Sender: TObject);
private
FMyWaitThread : TMyWaitThread;
Fwaiting: Boolean;
procedure WM_WAITINGDONE(var msg : TMessage); message WM_WATINGDONE;
procedure Setwaiting(const Value: Boolean);
{ Private declarations }
property waiting : Boolean read Fwaiting write Setwaiting;
procedure WatingDone;


public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnWaitClick(Sender: TObject);
var
dt : TDateTime;
begin
dt := cxDateEdit1.EditValue;
FMyWaitThread.SetWaitTime(dt);
waiting := True;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
cxClock1.Time := now;
Timer1.Enabled := True;
waiting := False;

FMyWaitThread := TMyWaitThread.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
FMyWaitThread.Terminate;
FreeAndNil(FMyWaitThread);
end;

procedure TForm1.Setwaiting(const Value: Boolean);
begin
Fwaiting := Value;
case Fwaiting of
True : begin
btnWait.Enabled := False;
end;

false : begin
btnWait.Enabled := True;
cxDateEdit1.EditValue := IncMinute(Now, 1);
end;
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
cxClock1.Time := now;
end;

procedure TForm1.WatingDone;
begin
waiting := False;
end;

procedure TForm1.WM_WAITINGDONE(var msg: TMessage);
begin
waiting := False;
end;

{ TMyWaitThread }

function GetGUID : string;
var
uid : TGUID;
r : Integer;
begin
Result := '';
r := CreateGuid(Uid);
if r = S_OK then
begin
Result := StringReplace(GuidToString(Uid),'{', '', [rfReplaceAll]);
Result := StringReplace(result, '}', '', [rfReplaceAll]);
end;
end;

constructor TMyWaitThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FWaitTimer := CreateWaitableTimer(nil, True, PWideChar(GetGUID)); // change the 'MatrixTimer' to something unique...
FTerminateEvent := TEvent.Create;
FPeriodicTimer := TADTimer.Create;
FPeriodicTimer.Interval := 10000;
end;

destructor TMyWaitThread.Destroy;
begin
FPeriodicTimer.StopTimer;
FreeAndNil(FPeriodicTimer);
FreeAndNil(FTerminateEvent);
CloseHandle(FWaitTimer);
inherited;
end;

procedure TMyWaitThread.execute;
var
EventArr : array of THandle;
begin
SetLength(EventArr, 3);

EventArr[0] := FTerminateEvent.Handle;
EventArr[1] := FWaitTimer;
EventArr[2] := FPeriodicTimer.Handle;

while not Terminated do
begin
try
case WaitForMultipleObjects(Length(EventArr), @EventArr[0], False, INFINITE) of

WAIT_OBJECT_0 : begin // terminate
OutputDebugString('Terminating.....');
Exit;
end;

WAIT_OBJECT_0+1 : begin // wait timer
OutputDebugString('Wait timer was triggered');

WaitTime := IncMinute(now, 1);

// How do I reset the FWaitTimer - I would like to keep the FWaitTimer handle so closing it is no good.

PostMessage(Form1.Handle, WM_WATINGDONE, 0, 0);
end;

WAIT_OBJECT_0+2 : begin // periodic timer
OutputDebugString('Periodic timer was triggered');
end;

end;

except on E: Exception do
// keep any exceptions inside the loop
end;
end;
end;

procedure TMyWaitThread.SetWaitTime(const Value: TDateTime);
var
WakeUpTime: LARGE_INTEGER;
SysTime : _SystemTime;
FTime : _FileTime;
begin
FWaitTime := Value;
DateTimeToSystemTime(FWaitTime, SysTime);
SystemTimeToFileTime(SysTime, FTime);
LocalFileTimeToFileTime(FTime, FTime);
WakeUpTime.LowPart := FTime.dwLowDateTime;
WakeUpTime.HighPart := FTime.dwHighDateTime;
SetWaitableTimer(FWaitTimer, WakeUpTime.quadpart, 0, nil, nil, True);
end;

procedure TMyWaitThread.Terminate;
begin
FTerminateEvent.SetEvent;
inherited;
end;

constructor TMyWaitThread.Create;
begin
Create(False);
end;

end.

最佳答案

引自 documentation (强调我的):

The thread calls the SetWaitableTimer function to activate the timer. Note the use of the following parameters for SetWaitableTimer: Use the lpDueTime parameter to specify the time at which the timer is to be set to the signaled state. When a manual-reset timer is set to the signaled state, it remains in this state until SetWaitableTimer establishes a new due time. When a synchronization timer is set to the signaled state, it remains in this state until a thread completes a wait operation on the timer object.

所以唯一的方法是再次调用SetWaitableTimer来重置计时器的信号状态。

有两种方法可以解决您的问题,使用当前的 hack,但在 SetWaitableTimer() 之后添加 CancelWaitableTimer() 来取消计时器(其状态将保持无信号状态)

更好的解决方案是在定时器不使用时不等待它,按照 @RbMm 建议实现:

put the FWaitTimer at the 2(last) place in array - EventArr[2] := FWaitTimer and pass 3 or 2 as first argument to WaitForMultipleObjects

关于delphi - 重置有信号的可等待计时器对象句柄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56441290/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com