|
|
@@ -10,7 +10,7 @@ unit uutlGenerics; |
|
|
|
interface |
|
|
|
|
|
|
|
uses |
|
|
|
Classes, SysUtils, typinfo, syncobjs; |
|
|
|
Classes, SysUtils, typinfo, uutlSyncObjs; |
|
|
|
|
|
|
|
type |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -328,8 +328,6 @@ type |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
{ Lock-Free Queue for single Producer / Consumer calls; |
|
|
|
Producer and Consumer are synchronized with SpinLocks } |
|
|
|
generic TutlQueue<T> = class(TObject) |
|
|
|
public type |
|
|
|
PListItem = ^TListItem; |
|
|
@@ -342,8 +340,6 @@ type |
|
|
|
protected |
|
|
|
fFirst: PListItem; |
|
|
|
fLast: PListItem; |
|
|
|
fFirstLock: Cardinal; |
|
|
|
fLastLock: Cardinal; |
|
|
|
fCount: Integer; |
|
|
|
fOwnsObjects: Boolean; |
|
|
|
public |
|
|
@@ -358,6 +354,19 @@ type |
|
|
|
destructor Destroy; override; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
generic TutlSyncQueue<T> = class(specialize TutlQueue<T>) |
|
|
|
private |
|
|
|
fPushLock: TutlSpinLock; |
|
|
|
fPopLock: TutlSpinLock; |
|
|
|
public |
|
|
|
procedure Push(const aItem: T); override; |
|
|
|
function Pop(out aItem: T): Boolean; override; |
|
|
|
|
|
|
|
constructor Create(const aOwnsObjects: Boolean = true); |
|
|
|
destructor Destroy; override; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
generic TutlInterfaceList<T> = class(TInterfaceList) |
|
|
|
private type |
|
|
@@ -410,7 +419,7 @@ type |
|
|
|
fFillState: integer; |
|
|
|
fWritePtr, fReadPtr: integer; |
|
|
|
fWrittenEvent, |
|
|
|
fReadEvent: TEvent; |
|
|
|
fReadEvent: TutlAutoResetEvent; |
|
|
|
public |
|
|
|
constructor Create(const Elements: Integer); |
|
|
|
destructor Destroy; override; |
|
|
@@ -426,7 +435,7 @@ type |
|
|
|
implementation |
|
|
|
|
|
|
|
uses |
|
|
|
uutlExceptions, uutlThreads; |
|
|
|
uutlExceptions, syncobjs; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//Helper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -1288,19 +1297,12 @@ procedure TutlQueue.Push(const aItem: T); |
|
|
|
var |
|
|
|
p: PListItem; |
|
|
|
begin |
|
|
|
// do as much as possible outside of the lock |
|
|
|
new(p); |
|
|
|
p^.data := aItem; |
|
|
|
p^.next := nil; |
|
|
|
|
|
|
|
while (InterLockedExchange(fLastLock, 1) <> 0) do; |
|
|
|
try |
|
|
|
fLast^.next := p; // is protected by fCount (if fCount = 0 then fLast = fFirst, |
|
|
|
fLast := fLast^.next; // so pop must always check fCount, before touching fFirst) |
|
|
|
InterLockedIncrement(fCount); |
|
|
|
finally |
|
|
|
InterLockedExchange(fLastLock, 0); |
|
|
|
end; |
|
|
|
fLast^.next := p; |
|
|
|
fLast := fLast^.next; |
|
|
|
InterLockedIncrement(fCount); |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -1308,22 +1310,15 @@ function TutlQueue.Pop(out aItem: T): Boolean; |
|
|
|
var |
|
|
|
old: PListItem; |
|
|
|
begin |
|
|
|
// do as much as possible outside of the lock |
|
|
|
result := false; |
|
|
|
FillByte(aItem{%H-}, SizeOf(aItem), 0); |
|
|
|
|
|
|
|
while (InterLockedExchange(fFirstLock, 1) <> 0) do; |
|
|
|
try |
|
|
|
if (Count <= 0) then |
|
|
|
exit; |
|
|
|
result := true; |
|
|
|
old := fFirst; |
|
|
|
fFirst := fFirst^.next; |
|
|
|
aItem := fFirst^.data; |
|
|
|
InterLockedDecrement(fCount); |
|
|
|
finally |
|
|
|
InterLockedExchange(fFirstLock, 0); |
|
|
|
end; |
|
|
|
if (Count <= 0) then |
|
|
|
exit; |
|
|
|
result := true; |
|
|
|
old := fFirst; |
|
|
|
fFirst := fFirst^.next; |
|
|
|
aItem := fFirst^.data; |
|
|
|
InterLockedDecrement(fCount); |
|
|
|
Dispose(old); |
|
|
|
end; |
|
|
|
|
|
|
@@ -1349,8 +1344,6 @@ begin |
|
|
|
new(fFirst); |
|
|
|
FillByte(fFirst^, SizeOf(fFirst^), 0); |
|
|
|
fLast := fFirst; |
|
|
|
fFirstLock := 0; |
|
|
|
fLastLock := 0; |
|
|
|
fCount := 0; |
|
|
|
fOwnsObjects := aOwnsObjects; |
|
|
|
end; |
|
|
@@ -1366,6 +1359,46 @@ begin |
|
|
|
inherited Destroy; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//TutlSyncQueue///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
procedure TutlSyncQueue.Push(const aItem: T); |
|
|
|
begin |
|
|
|
fPushLock.Enter; |
|
|
|
try |
|
|
|
inherited Push(aItem); |
|
|
|
finally |
|
|
|
fPushLock.Leave; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
function TutlSyncQueue.Pop(out aItem: T): Boolean; |
|
|
|
begin |
|
|
|
fPopLock.Enter; |
|
|
|
try |
|
|
|
result := inherited Pop(aItem); |
|
|
|
finally |
|
|
|
fPopLock.Leave; |
|
|
|
end; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
constructor TutlSyncQueue.Create(const aOwnsObjects: Boolean); |
|
|
|
begin |
|
|
|
inherited Create(aOwnsObjects); |
|
|
|
fPushLock := TutlSpinLock.Create; |
|
|
|
fPopLock := TutlSpinLock.Create; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
destructor TutlSyncQueue.Destroy; |
|
|
|
begin |
|
|
|
inherited Destroy; //inherited will pop all remaining items, so do not destroy spinlock before! |
|
|
|
FreeAndNil(fPushLock); |
|
|
|
FreeAndNil(fPopLock); |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//TutlInterfaceList.TInterfaceEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
@@ -1565,8 +1598,8 @@ begin |
|
|
|
fWritePtr:= 1; |
|
|
|
fReadPtr:= 0; |
|
|
|
fFillState:= 0; |
|
|
|
fReadEvent:= TAutoResetEvent.Create; |
|
|
|
fWrittenEvent:= TAutoResetEvent.Create; |
|
|
|
fReadEvent:= TutlAutoResetEvent.Create; |
|
|
|
fWrittenEvent:= TutlAutoResetEvent.Create; |
|
|
|
end; |
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|