Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Arbeiten mit TThreadlist

  Alt 19. Jan 2017, 23:46
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.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat