Jetzt alle relevanten Methoden in Enter/Leave zu klammern halte ich für wenig hilfreich, denn das sind in non-threadsafe Fall immer zwei überflüssige Calls. Davon abgesehen wird das in einigen Fällen auch nicht reichen, z.B. wenn man erwartet, dass ein Peek gefolgt von einem Pop ein konsistentes Ergebnis liefert. Aber auch das property Notify ist mit dem direkten Feldzugriff nicht wirklich threadsicher.
TRingBuffer
in einer thread-safe Version ableiten läuft konträr zur aktuellen Ableitungsphilosophie mit
TObjectRingbuffer
. Man müsste dann womöglich jede Ableitung in zwei Flavors machen:
TRingbuffer<T> -> TThreadsafeRingBuffer<T>
TObjectRingbuffer<T:class> -> TThreadsafeObjectRingbuffer<T:class>
Das erscheint mir nicht sonderlich sinnvoll.
Ein möglicher Ansatz, der den ursprünglichen Ringbuffer unangetastet lässt, wäre ein Wrapper für den Zugriff - analog zu
TThreadList
:
Delphi-Quellcode:
type
TThreadRingBufferWrapper<T> = class
private
FLock: TObject;
FRingBuffer: TRingBuffer<T>;
public
constructor Create(ARingBuffer: TRingBuffer<T>);
destructor Destroy; override;
function LockBuffer: TRingBuffer<T>;
procedure UnlockBuffer; inline;
end;
...
constructor TThreadRingBufferWrapper<T>.Create(ARingBuffer: TRingBuffer<T>);
begin
inherited Create;
FRingBuffer := ARingBuffer;
FLock := TObject.Create();
end;
destructor TThreadRingBufferWrapper<T>.Destroy;
begin
LockBuffer;
try
FRingBuffer.Free;
inherited Destroy;
finally
UnlockBuffer;
FLock.Free;
end;
end;
function TThreadRingBufferWrapper<T>.LockBuffer: TRingBuffer<T>;
begin
TMonitor.Enter(FLock);
Result := FRingBuffer;
end;
procedure TThreadRingBufferWrapper<T>.UnlockBuffer;
begin
TMonitor.Exit(FLock);
end;