Wozu dient aber die Zuweisung zu myList
Die eigentliche
TThreadList
ist keine Liste, sondern verwaltet nur intern eine Solche. Konkret macht
LockList
folgendes:
Delphi-Quellcode:
function TThreadList.LockList: TList;
begin
TMonitor.Enter(FLock);
Result := FList;
end;
und
UnlockList
dies:
Delphi-Quellcode:
procedure TThreadList.UnlockList;
begin
TMonitor.Exit(FLock);
end;
und was, wenn ich die Liste so abarbeiten würde:
Delphi-Quellcode:
myList:= threadList1.LockList;
myList:= threadList1.UnLockList; // Gleich nach Zuweisung wieder freigeben
Naja, das wäre gleichbedeutend mit dem kompletten Weglassen von
TThreadList
; sprich: Du operierst praktisch auf einer normalen Liste, welche entsprechend nicht Thread-safe ist.
Zum Verständnis:
Sobald
TMonitor.Enter
von einem deiner beiden Threads aufgerufen wurde, erhält dieser Thread exklusiven Zugriff, bis er selbst
TMonitor.Exit
erreicht. Hat ein Thread den exklusiven Zugriff, dann hält der zweite Thread in dem Moment, in dem er auch
TMonitor.Enter
erreicht (vereinfacht ausgedrückt) einfach an - und zwar so lange, bis der erste Thread den exklusiven Zugriff durch den Aufruf von
TMonitor.Exit
wieder abgibt. So ist garantiert, dass der abgesicherte Code-Block tatsächlich nicht konkurrierend abgearbeitet werden kann und keine Dateninkohärenzen entstehen.
In der Praxis ist es aber so, dass ich in der Regel schneller Schreiben kann als ich erzeuge. Nur hin und wieder kommt es zu Engpässen und dann will ich puffern.
Wie erreiche ich es dass die Liste nur kürzestmöglich gelockt ist damit sie wieder Daten empfangen kann
Das ist gut
In diesem Falle würde ich dir zu so einem von mir beschriebenen RingBuffer raten. Mit
TInterlocked.Read
,
TInterlocked.Exchange
,
TInterlocked.CompareExchange
,
TInterlocked.Increment
und
TInterlocked.Decrement
stehen dir eine Reihe von atomaren Instruktionen zur Verfügung, welche alle nur eine Hand von CPU Zyklen verbrauchen (und demnach alle anderen Threads bei konkurrierenden Zugriffen auch nur für diese kurze Zeit blockieren).
Eine vielleicht einfachere Alternative wäre deine momentane Methode beizubehalten, allerdings darauf zu achten, dass du im Producer Thread die Liste tatsächlich NUR für den Augenblick lockst, in dem du das neue Element mit
Add
hinzufügst. Im Consumer könntest du die Liste locken, alle Daten in eine lokale (temporäre) zweite Liste kopieren, danach die gemeinsame Liste leeren und unlocken. Danach beginnst du auf der temporären Liste deinen Loop abzuarbeiten. Bei dieser Vorgehensweise sollten beide Threads nur kurze Zeit blockiert werden und der Producer muss vor allem nicht darauf warten, bis sämtliche Werte in die Datenbank geschrieben wurden.