CEF4Delphi/source/uCEFWorkSchedulerQueueThread.pas
2023-09-24 11:21:05 +02:00

236 lines
4.9 KiB
ObjectPascal

unit uCEFWorkSchedulerQueueThread;
{$IFDEF FPC}
{$MODE OBJFPC}{$H+}
{$ENDIF}
{$I cef.inc}
{$IFNDEF TARGET_64BITS}{$ALIGN ON}{$ENDIF}
{$MINENUMSIZE 4}
interface
uses
{$IFDEF DELPHI16_UP}
System.Classes, System.SyncObjs, System.SysUtils,
{$ELSE}
Classes, SyncObjs, SysUtils,
{$ENDIF}
uCEFConstants;
type
TOnPulseEvent = procedure(Sender: TObject; aDelay: integer) of object;
TValuesArray = array of integer;
TCEFWorkSchedulerQueueThread = class(TThread)
protected
FQueueCS : TCriticalSection;
FEvent : TEvent;
FWaiting : boolean;
FStop : boolean;
FReady : boolean;
FValues : TValuesArray;
FOnPulse : TOnPulseEvent;
function GetAvailableValue : integer;
function GetHasPendingValue : boolean;
function Lock : boolean;
procedure Unlock;
function CanContinue : boolean;
procedure ReadAllPendingValues;
procedure DoOnPulse;
procedure Execute; override;
property AvailableValue : integer read GetAvailableValue;
property HasPendingValue : boolean read GetHasPendingValue;
public
constructor Create;
destructor Destroy; override;
procedure AfterConstruction; override;
procedure StopThread;
procedure EnqueueValue(aValue : integer);
property Ready : boolean read FReady;
property OnPulse : TOnPulseEvent read FOnPulse write FOnPulse;
end;
implementation
constructor TCEFWorkSchedulerQueueThread.Create;
begin
inherited Create(True);
FReady := False;
FQueueCS := nil;
FWaiting := False;
FStop := False;
FEvent := nil;
FValues := nil;
FOnPulse := nil;
FreeOnTerminate := False;
end;
destructor TCEFWorkSchedulerQueueThread.Destroy;
begin
if (FEvent <> nil) then FreeAndNil(FEvent);
if (FQueueCS <> nil) then FreeAndNil(FQueueCS);
if (FValues <> nil) then
begin
Finalize(FValues);
FValues := nil;
end;
inherited Destroy;
end;
procedure TCEFWorkSchedulerQueueThread.AfterConstruction;
begin
inherited AfterConstruction;
FEvent := TEvent.Create(nil, False, False, '');
FQueueCS := TCriticalSection.Create;
end;
function TCEFWorkSchedulerQueueThread.Lock : boolean;
begin
if (FQueueCS <> nil) then
begin
FQueueCS.Acquire;
Result := True;
end
else
Result := False;
end;
procedure TCEFWorkSchedulerQueueThread.Unlock;
begin
if (FQueueCS <> nil) then FQueueCS.Release;
end;
function TCEFWorkSchedulerQueueThread.GetAvailableValue : integer;
var
TempLen : integer;
TempNewValues : TValuesArray;
begin
Result := 0;
if Lock then
try
TempLen := length(FValues);
if (TempLen > 0) then
begin
Result := FValues[0];
if (TempLen = 1) then
SetLength(FValues, 0)
else
begin
SetLength(TempNewValues, TempLen - 1);
TempNewValues := copy(FValues, 1, high(integer));
SetLength(FValues, length(TempNewValues));
FValues := Copy(TempNewValues);
Finalize(TempNewValues);
end;
end;
finally
Unlock;
end;
end;
function TCEFWorkSchedulerQueueThread.GetHasPendingValue : boolean;
begin
Result := False;
if Lock then
try
if not(Terminated) and not(FStop) then
begin
FWaiting := False;
Result := (Length(FValues) > 0);
end;
finally
Unlock;
end;
end;
procedure TCEFWorkSchedulerQueueThread.StopThread;
begin
if Lock then
try
FStop := True;
if FWaiting then
begin
FWaiting := False;
FEvent.SetEvent;
end;
finally
Unlock;
end;
end;
procedure TCEFWorkSchedulerQueueThread.EnqueueValue(aValue : integer);
begin
if Lock then
try
SetLength(FValues, Length(FValues) + 1);
FValues[Length(FValues) - 1] := aValue;
if FWaiting then
begin
FWaiting := False;
FEvent.SetEvent;
end;
finally
Unlock;
end;
end;
procedure TCEFWorkSchedulerQueueThread.ReadAllPendingValues;
begin
while HasPendingValue do
if not(Terminated) then
Synchronize({$IFDEF FPC}self, @{$ENDIF}DoOnPulse);
end;
procedure TCEFWorkSchedulerQueueThread.DoOnPulse;
begin
if assigned(FOnPulse) then
FOnPulse(self, AvailableValue);
end;
function TCEFWorkSchedulerQueueThread.CanContinue : boolean;
begin
Result := False;
if Lock then
try
if not(Terminated) and not(FStop) then
begin
Result := True;
FWaiting := True;
FEvent.ResetEvent;
end;
finally
Unlock;
end;
end;
procedure TCEFWorkSchedulerQueueThread.Execute;
begin
FReady := True;
while CanContinue do
begin
FEvent.WaitFor(INFINITE);
ReadAllPendingValues;
end;
end;
end.