Is it possible to restart TEvent.WaitFor
without exiting it? I need to start waiting again when _interval
was changed by setter. For example, when one hour was set and I would like to change interval to 15 seconds, changes will come into effect when one hour is elapsed.
_terminatingEvent: TEvent;
procedure TTimerThread.Execute();
begin
inherited;
while not Terminated do begin
try
_terminatingEvent.WaitFor(_interval);
if Assigned(_onTimer) and _enabled then _onTimer(Self);
except
on ex: Exception do _logError(ex);
end;
end;
end;
procedure TTimerThread.TerminatedSet();
begin
_terminatingEvent.SetEvent();
end;
procedure TTimerThread._setInterval(const Value: Integer);
begin
_interval := Value;
//Restart WaitFor here
end;
Currently I "solved" the issue in a following way:
procedure TTimerThread.Execute();
begin
inherited;
while not Terminated do begin
try
if _terminatingEvent.WaitFor(_interval) = wrTimeout then
if Assigned(_onTimer) and _enabled then _onTimer(Self);
except
on ex: Exception do _logError(ex);
end;
end;
end;
procedure TTimerThread.TerminatedSet();
begin
_terminatingEvent.SetEvent();
end;
procedure TTimerThread._setInterval(const Value: Integer);
begin
_interval := Value;
_terminatingEvent.ResetEvent();
end;
It seems that when I use SetEvent
instead of ResetEvent
, the "set" state is saved permanently and CPU usage jumps to 100%.
You can use two TEvent
objects, one for the timer and one for the setter, eg:
type
TTimerThread = class(TThread)
private
_terminatingEvent: TEvent;
_updatedEvent: TEvent;
...
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
constructor Create(ASuspended: Boolean); reintroduce;
destructor Destroy; override;
end;
constructor TTimerThread.Create(ASuspended: Boolean);
begin
inherited Create(ASuspended);
_terminatingEvent := TEvent.Create(nil, True, False, '');
_updatedEvent := TEvent.Create(nil, False, False, '');
end;
destructor TTimerThread.Destroy;
begin
_terminatingEvent.Free;
_updatedEvent.Free;
inherited;
end;
procedure TTimerThread.Execute;
var
Arr: THandleObjectArray;
SignaledObj: THandleObject;
begin
SetLength(Arr, 2);
Arr[0] := _terminatingEvent;
Arr[1] := _updatedEvent;
while not Terminated do
begin
try
case THandleObject.WaitForMultiple(Arr, _interval, False, SignaledObj) of
wrSignaled: begin
if (SignaledObj is TEvent) then (SignaledObj as TEvent).ResetEvent();
end;
wrTimeOut: begin
if Assigned(_onTimer) and _enabled then
_onTimer(Self);
end;
wrError: begin
RaiseLastOSError;
end;
end;
except
on ex: Exception do
_logError(ex);
end;
end;
end;
procedure TTimerThread.TerminatedSet;
begin
inherited;
_terminatingEvent.SetEvent;
end;
procedure TTimerThread._setInterval(const Value: Integer);
begin
if _interval <> Value then
begin
_interval := Value;
_updatedEvent.SetEvent;
end;
end;