重新启动 TEvent.WaitFor 而不退出
Restart TEvent.WaitFor without exiting it
是否可以在不退出的情况下重新启动TEvent.WaitFor
?当 _interval
被 setter 更改时,我需要重新开始等待。比如设置了一个小时,我想把间隔时间改成15秒,经过一小时后更改才会生效。
_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;
目前我"solved"通过以下方式解决问题:
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;
似乎当我使用 SetEvent
而不是 ResetEvent
时,"set" 状态被永久保存并且 CPU 使用率跃升至 100%。
最后我使用了SetEvent
和ResetEvent
的组合。如果有人有更好的答案,我会采纳。
procedure TTimerThread.Execute();
begin
inherited;
while not Terminated do begin
try
case _terminatingEvent.WaitFor(_interval) of
wrTimeout: if Assigned(_onTimer) and _enabled then _onTimer(Self);
wrSignaled: _terminatingEvent.ResetEvent();
end;
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.SetEvent();
end;
procedure TTimerThread._setEnabled(const Value: Boolean);
begin
if _enabled = Value then Exit();
_enabled := Value;
if _enabled and Suspended then Suspended := False;
_terminatingEvent.SetEvent();
end;
您可以使用两个 TEvent
对象,一个用于计时器,一个用于 setter,例如:
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;
是否可以在不退出的情况下重新启动TEvent.WaitFor
?当 _interval
被 setter 更改时,我需要重新开始等待。比如设置了一个小时,我想把间隔时间改成15秒,经过一小时后更改才会生效。
_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;
目前我"solved"通过以下方式解决问题:
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;
似乎当我使用 SetEvent
而不是 ResetEvent
时,"set" 状态被永久保存并且 CPU 使用率跃升至 100%。
最后我使用了SetEvent
和ResetEvent
的组合。如果有人有更好的答案,我会采纳。
procedure TTimerThread.Execute();
begin
inherited;
while not Terminated do begin
try
case _terminatingEvent.WaitFor(_interval) of
wrTimeout: if Assigned(_onTimer) and _enabled then _onTimer(Self);
wrSignaled: _terminatingEvent.ResetEvent();
end;
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.SetEvent();
end;
procedure TTimerThread._setEnabled(const Value: Boolean);
begin
if _enabled = Value then Exit();
_enabled := Value;
if _enabled and Suspended then Suspended := False;
_terminatingEvent.SetEvent();
end;
您可以使用两个 TEvent
对象,一个用于计时器,一个用于 setter,例如:
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;