mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-19 13:21:46 +02:00
lazcollections: TLazThreadedQueue refactor into threaded/none-threaded part
git-svn-id: trunk@63861 -
This commit is contained in:
parent
144fb11c00
commit
c5e7f1e250
@ -36,22 +36,45 @@ type
|
|||||||
class property DefaultSpinCount: integer read GetDefaultSpinCount write SetDefaultSpinCount;
|
class property DefaultSpinCount: integer read GetDefaultSpinCount write SetDefaultSpinCount;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TThreadedQueue }
|
{ TLazFifoQueue }
|
||||||
|
|
||||||
|
generic TLazFifoQueue<T> = class
|
||||||
|
private
|
||||||
|
FList: array of T;
|
||||||
|
FQueueSize: integer;
|
||||||
|
FTotalItemsPopped: QWord;
|
||||||
|
FTotalItemsPushed: QWord;
|
||||||
|
function GetIsEmpty: Boolean;
|
||||||
|
function GetIsFull: Boolean;
|
||||||
|
public
|
||||||
|
constructor create(AQueueDepth: Integer = 10);
|
||||||
|
procedure Grow(ADelta: integer);
|
||||||
|
function PushItem(const AItem: T): Boolean; virtual;
|
||||||
|
function PopItem(out AItem: T): Boolean; virtual;
|
||||||
|
property QueueSize: integer read FQueueSize;
|
||||||
|
property TotalItemsPopped: QWord read FTotalItemsPopped;
|
||||||
|
property TotalItemsPushed: QWord read FTotalItemsPushed;
|
||||||
|
property IsEmpty: Boolean read GetIsEmpty;
|
||||||
|
property IsFull: Boolean read GetIsFull;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TLazThreadedQueue }
|
{ TLazThreadedQueue }
|
||||||
|
|
||||||
generic TLazThreadedQueue<T> = class
|
generic TLazThreadedQueue<T> = class
|
||||||
|
protected
|
||||||
|
type
|
||||||
|
TLazTypedFifoQueue = specialize TLazFifoQueue<T>;
|
||||||
private
|
private
|
||||||
FMonitor: TLazMonitor;
|
FMonitor: TLazMonitor;
|
||||||
FList: array of T;
|
FFifoList: TLazTypedFifoQueue;
|
||||||
FPushTimeout: Cardinal;
|
FPushTimeout: Cardinal;
|
||||||
FPopTimeout: Cardinal;
|
FPopTimeout: Cardinal;
|
||||||
FQueueSize: integer;
|
|
||||||
FTotalItemsPopped: QWord;
|
|
||||||
FTotalItemsPushed: QWord;
|
|
||||||
FHasRoomEvent: PRTLEvent;
|
FHasRoomEvent: PRTLEvent;
|
||||||
FHasItemEvent: PRTLEvent;
|
FHasItemEvent: PRTLEvent;
|
||||||
FShutDown: boolean;
|
FShutDown: boolean;
|
||||||
|
function GetQueueSize: integer; inline;
|
||||||
|
function GetTotalItemsPopped: QWord; inline;
|
||||||
|
function GetTotalItemsPushed: QWord; inline;
|
||||||
function TryPushItem(const AItem: T): boolean; inline;
|
function TryPushItem(const AItem: T): boolean; inline;
|
||||||
function TryPopItem(out AItem: T): boolean; inline;
|
function TryPopItem(out AItem: T): boolean; inline;
|
||||||
protected
|
protected
|
||||||
@ -59,6 +82,7 @@ type
|
|||||||
function TryPopItemUnprotected(out AItem: T): boolean;
|
function TryPopItemUnprotected(out AItem: T): boolean;
|
||||||
procedure Lock;
|
procedure Lock;
|
||||||
procedure Unlock;
|
procedure Unlock;
|
||||||
|
function CreateFifoQueue(AQueueDepth: Integer): TLazTypedFifoQueue; virtual;
|
||||||
public
|
public
|
||||||
constructor create(AQueueDepth: Integer = 10; PushTimeout: cardinal = INFINITE; PopTimeout: cardinal = INFINITE);
|
constructor create(AQueueDepth: Integer = 10; PushTimeout: cardinal = INFINITE; PopTimeout: cardinal = INFINITE);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -67,9 +91,9 @@ type
|
|||||||
function PopItem(out AItem: T): TWaitResult;
|
function PopItem(out AItem: T): TWaitResult;
|
||||||
function PopItemTimeout(out AItem: T; Timeout: cardinal): TWaitResult;
|
function PopItemTimeout(out AItem: T; Timeout: cardinal): TWaitResult;
|
||||||
procedure DoShutDown;
|
procedure DoShutDown;
|
||||||
property QueueSize: integer read FQueueSize;
|
property QueueSize: integer read GetQueueSize;
|
||||||
property TotalItemsPopped: QWord read FTotalItemsPopped;
|
property TotalItemsPopped: QWord read GetTotalItemsPopped;
|
||||||
property TotalItemsPushed: QWord read FTotalItemsPushed;
|
property TotalItemsPushed: QWord read GetTotalItemsPushed;
|
||||||
property ShutDown: boolean read FShutDown;
|
property ShutDown: boolean read FShutDown;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -150,6 +174,61 @@ begin
|
|||||||
inherited Acquire;
|
inherited Acquire;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TLazFifoQueue }
|
||||||
|
|
||||||
|
function TLazFifoQueue.GetIsEmpty: Boolean;
|
||||||
|
begin
|
||||||
|
result := FTotalItemsPushed = FTotalItemsPopped;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLazFifoQueue.GetIsFull: Boolean;
|
||||||
|
begin
|
||||||
|
result := FTotalItemsPushed - FTotalItemsPopped = FQueueSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TLazFifoQueue.create(AQueueDepth: Integer);
|
||||||
|
begin
|
||||||
|
Grow(AQueueDepth);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TLazFifoQueue.Grow(ADelta: integer);
|
||||||
|
var
|
||||||
|
NewList: array of T;
|
||||||
|
c: Integer;
|
||||||
|
i: QWord;
|
||||||
|
begin
|
||||||
|
c:=Max(FQueueSize + ADelta, Integer(FTotalItemsPushed - FTotalItemsPopped));
|
||||||
|
setlength(NewList, c);
|
||||||
|
i:=FTotalItemsPopped;
|
||||||
|
while i < FTotalItemsPushed do begin
|
||||||
|
NewList[i mod c] := FList[i mod FQueueSize];
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
FList := NewList;
|
||||||
|
FQueueSize:=c;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLazFifoQueue.PushItem(const AItem: T): Boolean;
|
||||||
|
begin
|
||||||
|
result := FTotalItemsPushed-FTotalItemsPopped<FQueueSize;
|
||||||
|
if result then
|
||||||
|
begin
|
||||||
|
FList[FTotalItemsPushed mod FQueueSize]:=AItem;
|
||||||
|
inc(FTotalItemsPushed);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLazFifoQueue.PopItem(out AItem: T): Boolean;
|
||||||
|
begin
|
||||||
|
result := FTotalItemsPushed>FTotalItemsPopped;
|
||||||
|
if result then
|
||||||
|
begin
|
||||||
|
AItem := FList[FTotalItemsPopped mod FQueueSize];
|
||||||
|
inc(FTotalItemsPopped);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TThreadedQueue }
|
{ TThreadedQueue }
|
||||||
|
|
||||||
function TLazThreadedQueue.TryPushItem(const AItem: T): boolean;
|
function TLazThreadedQueue.TryPushItem(const AItem: T): boolean;
|
||||||
@ -162,6 +241,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TLazThreadedQueue.GetQueueSize: integer;
|
||||||
|
begin
|
||||||
|
Result := FFifoList.QueueSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLazThreadedQueue.GetTotalItemsPopped: QWord;
|
||||||
|
begin
|
||||||
|
Result := FFifoList.TotalItemsPopped;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLazThreadedQueue.GetTotalItemsPushed: QWord;
|
||||||
|
begin
|
||||||
|
Result := FFifoList.TotalItemsPushed;
|
||||||
|
end;
|
||||||
|
|
||||||
function TLazThreadedQueue.TryPopItem(out AItem: T): boolean;
|
function TLazThreadedQueue.TryPopItem(out AItem: T): boolean;
|
||||||
begin
|
begin
|
||||||
FMonitor.Enter;
|
FMonitor.Enter;
|
||||||
@ -174,29 +268,23 @@ end;
|
|||||||
|
|
||||||
function TLazThreadedQueue.TryPushItemUnprotected(const AItem: T): boolean;
|
function TLazThreadedQueue.TryPushItemUnprotected(const AItem: T): boolean;
|
||||||
begin
|
begin
|
||||||
result := FTotalItemsPushed-FTotalItemsPopped<FQueueSize;
|
result := FFifoList.PushItem(AItem);
|
||||||
if result then
|
if result then
|
||||||
begin
|
|
||||||
FList[FTotalItemsPushed mod FQueueSize]:=AItem;
|
|
||||||
inc(FTotalItemsPushed);
|
|
||||||
RTLeventSetEvent(FHasItemEvent);
|
RTLeventSetEvent(FHasItemEvent);
|
||||||
end;
|
|
||||||
RTLeventResetEvent(FHasRoomEvent);
|
RTLeventResetEvent(FHasRoomEvent);
|
||||||
if FTotalItemsPushed-FTotalItemsPopped<FQueueSize then
|
if not FFifoList.IsFull then
|
||||||
RTLeventSetEvent(FHasRoomEvent);
|
RTLeventSetEvent(FHasRoomEvent);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TLazThreadedQueue.TryPopItemUnprotected(out AItem: T): boolean;
|
function TLazThreadedQueue.TryPopItemUnprotected(out AItem: T): boolean;
|
||||||
begin
|
begin
|
||||||
result := FTotalItemsPushed>FTotalItemsPopped;
|
result := FFifoList.PopItem(AItem);
|
||||||
if result then
|
if result then
|
||||||
begin
|
|
||||||
AItem := FList[FTotalItemsPopped mod FQueueSize];
|
|
||||||
inc(FTotalItemsPopped);
|
|
||||||
RTLeventSetEvent(FHasRoomEvent);
|
RTLeventSetEvent(FHasRoomEvent);
|
||||||
end;
|
|
||||||
RTLeventResetEvent(FHasItemEvent);
|
RTLeventResetEvent(FHasItemEvent);
|
||||||
if FTotalItemsPushed > FTotalItemsPopped then
|
if not FFifoList.IsEmpty then
|
||||||
RTLeventSetEvent(FHasItemEvent);
|
RTLeventSetEvent(FHasItemEvent);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -210,9 +298,16 @@ begin
|
|||||||
FMonitor.Leave;
|
FMonitor.Leave;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TLazThreadedQueue.CreateFifoQueue(AQueueDepth: Integer
|
||||||
|
): TLazTypedFifoQueue;
|
||||||
|
begin
|
||||||
|
result := TLazTypedFifoQueue.create(AQueueDepth);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TLazThreadedQueue.create(AQueueDepth: Integer; PushTimeout: cardinal; PopTimeout: cardinal);
|
constructor TLazThreadedQueue.create(AQueueDepth: Integer; PushTimeout: cardinal; PopTimeout: cardinal);
|
||||||
begin
|
begin
|
||||||
FMonitor:=TLazMonitor.create;
|
FMonitor:=TLazMonitor.create;
|
||||||
|
FFifoList := CreateFifoQueue(AQueueDepth);
|
||||||
Grow(AQueueDepth);
|
Grow(AQueueDepth);
|
||||||
FHasRoomEvent:=RTLEventCreate;
|
FHasRoomEvent:=RTLEventCreate;
|
||||||
RTLeventSetEvent(FHasRoomEvent);
|
RTLeventSetEvent(FHasRoomEvent);
|
||||||
@ -227,6 +322,7 @@ begin
|
|||||||
RTLeventdestroy(FHasRoomEvent);
|
RTLeventdestroy(FHasRoomEvent);
|
||||||
RTLeventdestroy(FHasItemEvent);
|
RTLeventdestroy(FHasItemEvent);
|
||||||
FMonitor.Free;
|
FMonitor.Free;
|
||||||
|
FFifoList.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -238,16 +334,7 @@ var
|
|||||||
begin
|
begin
|
||||||
FMonitor.Enter;
|
FMonitor.Enter;
|
||||||
try
|
try
|
||||||
c:=Max(FQueueSize + ADelta, Integer(FTotalItemsPushed - FTotalItemsPopped));
|
FFifoList.Grow(ADelta);
|
||||||
setlength(NewList, c);
|
|
||||||
i:=FTotalItemsPopped;
|
|
||||||
while i < FTotalItemsPushed do begin
|
|
||||||
NewList[i mod c] := FList[i mod FQueueSize];
|
|
||||||
inc(i);
|
|
||||||
end;
|
|
||||||
|
|
||||||
FList := NewList;
|
|
||||||
FQueueSize:=c;
|
|
||||||
finally
|
finally
|
||||||
FMonitor.Leave;
|
FMonitor.Leave;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user