AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TThread: Synchronize() priorisieren?

Ein Thema von romber · begonnen am 29. Mär 2016 · letzter Beitrag vom 4. Apr 2016
Antwort Antwort
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#1

AW: TThread: Synchronize() priorisieren?

  Alt 29. Mär 2016, 16:32
Der Thread sollte gar nichts mit der Oberfläche zu tun haben sondern nur die jeweils aktuellen Daten bereitstellen. Wenn es neue Daten gibt, kann er ja ein Event auslösen und die Oberfläche zeigt die jeweils aktuellen Daten an wie sie grade Lust hat.
emm... nix anderes ist ein Syncronize... Ob Du nun wie Du im Beispiel den Event im Queue auslößt oder mit Sync es aus dem Thread selber machst... Ich erstmal "fast" kein Unterschied...

Bringt Queue() neben dem Vorteil, dass der Threadablauf nicht blockiert wird, irgendwelche Nachteile mit sich?
Man muss sich im klaren sein was wann passiert...

Beispiel für Queue aus dem Thread oder wie Günther es geschrieben hat ein Event dann die Daten von der anderen Seite aus holt...

Beispiel:

Ein Thread erzeugt permanent Daten und zwar nicht nur ein Integer sonst was kompliziertes...
Bei einem Syncronize musst du zwar warten auf den UI-Thread aber kannst sicher danach die Daten verwerfen...
Bei ein Queue Aufruf, musst Du sicher stellen, dass zum Zeitpunkt wo der UI-Thread die Daten darstellen will, die Daten auch noch vorhanden sind. Noch schwieriger ist es, wenn Du die Kontrolle - wie Günther - an ein anderes Programmteil übergeben hast... Denn falls der UI-Thread die Daten lesen will, muss sichergestellt werden, dass der Thread die Daten nicht gerade neu- oder überschreibt.

Musst Du alle Zwischenschritte immer darstellen? Ich habe hier z.B. eine Routine programmiert, die immer wenn der Thread neue Daten erzeugt und der UI-Thread die Daten noch nicht verarbeitet hat, der letzte Datensatz verworfen und sofort gegen den neuen Ausgetauscht wird.

Für Dein Problem, würde ich einfach 2 oder wie viele auch immer Du brauchst eigenen Threadsichere Queues erzeugen und diese über einen Workerthread der gemäß Priorität die einzelen Queues abarbeitet und dann problemlos Syncronisieren kann.

Mavarik
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.196 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: TThread: Synchronize() priorisieren?

  Alt 29. Mär 2016, 16:38
emm... nix anderes ist ein Syncronize...
Richtig, der benutzt auch TThread.Synchronize() oder .Queue() oder was auch immer. Es ging darum, den Thread nicht auf Gedeih und Verderb an irgendein Formular zu ketten sondern von außen festzulegen was geschehen soll. Vielleicht willst du auch nichts anzeigen, sondern nur loggen. Oder beides. Solche Anforderungen ändern sich ständig. Aber deshalb fasst man nicht ständig das Herzstück an.
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.154 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: TThread: Synchronize() priorisieren?

  Alt 29. Mär 2016, 16:46
emm... nix anderes ist ein Syncronize...
Richtig, der benutzt auch TThread.Synchronize() oder .Queue() oder was auch immer. Es ging darum, den Thread nicht auf Gedeih und Verderb an irgendein Formular zu ketten sondern von außen festzulegen was geschehen soll. Vielleicht willst du auch nichts anzeigen, sondern nur loggen. Oder beides. Solche Anforderungen ändern sich ständig. Aber deshalb fasst man nicht ständig das Herzstück an.
Kommt darauf an, wenn der Thread der "einzige" ist der weiß was richtig ist, geht es nicht anders...
Aber ich verstehe deinen Einwand/Ansatz!
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.688 Beiträge
 
Delphi 2007 Enterprise
 
#4

AW: TThread: Synchronize() priorisieren?

  Alt 29. Mär 2016, 19:25
Statt der Events via Methodenzeiger bevorzuge ich mittlerweile eine doppelt gepufferte Datenhaltung und Windows Messages. Beispiel:
Delphi-Quellcode:
// Threadklasse
type
  TMyThread = class(TThread)
  private
    FThreadBuffer: TObjectList; // Hier schreibt der Thread seine Daten rein
    FGUIBuffer: TObjectList; // Hier liest nachher die GUI raus
    FBufferCS: TCriticalSection;
    FForm: HWND;
    function GetItems: TObjectList;
    function GetItemCount: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create(aForm: HWND);
    procedure LockData;
    procedure ReleaseData;
    property Items: TObjectList read GetItems;
    property ItemCount: Integer read GetItemCount;
  end;

const
  WM_MY_DATA_UPDATE = WM_USER + 1234;

implementation
  
constructor TMyThread.Create(aForm: HWND);
begin
  inherited(false);
  FForm := aForm;
  // Initialisierung der Buffer etc.
end;

procedure TMyThread.LockData;
begin
  FBufferCS.Enter;
end;

procedure TMyThread.ReleaseData;
begin
  FBufferCS.Leave;
end;

procedure TMyThread.GetItems: TObjectList;
begin
  FBufferCS.Enter;
  try
    result := FGUIBuffer;
  finally
    FBufferCS.Leave;
  end;
end;

procedure TMyThread.Execute;
begin
  repeat
    DoSlowStuffWith(FThreadBuffer);

    FBufferCS.Enter;
    try
      FGUIBuffer.Clear; // OwnsObjects!
      CloneAllItemsFromThreadBufferTo(FGUIBuffer);
    finally
      FBufferCS.Leave;
      PostMessage(FForm, WM_MY_DATA_UPDATE, 0, 0);
    end;
  until Terminated;
end;
Delphi-Quellcode:
// Formularklasse
type
  TMainForm = class(TForm)
  private
    procedure OnMyDataUpdate(var msg: TMessage); message WM_MY_DATA_UPDATE;
  public
  end;

implementation

procedure TMainForm.OnMyDataUpdate(var msg: TMessage);
begin
  myThreadInstance.LockData;
  try
    WriteItemsToGrid(myThreadInstance.Items);
  finally
    myThreadInstance.ReleaseData;
  end;
end;
Dabei ist es dann recht egal wie lange es dauert die Daten im Thread zusammenzustellen, die GUI muss maximal auf das Kopieren der ListItems warten, was in wenigen Millisekunden erledigt ist. Dadurch wird die GUI wunderbar flott, egal wie riesig z.B. die Tabelle ist aus der die Daten erst abgerufen werden müssen im Thread. Zudem muss der Thread nicht erst warten bis die GUI all ihren Krams ins Grid gepackt hat, der kann ja ruhig schon mal den nächsten Zyklus abrufen.

UND: Es ist dem Thread an sich völlig egal wer seine Daten abholt, wie der Abholer sie dann interpretiert, und ob überhaupt ein Abholer vorhanden ist.

Der Code ist natürlich nur eine ganz grobe pseudocodeähnliche Skizze, und je nach Anwendungsfall kommen natürlich auch mehrere verschiedene Buffer in Frage. Auch der Typ der Buffer ist an sich egal, wichtig ist nur, dass wirklich KOPIEN existieren, nicht nur Referenzen auf dieselben Instanzen in die der Thread rein schreibt. Auch ist ein Queue-ähnlicher Aufbau denkbar, bei dem erst Items in die Thread-Liste gefüllt werden, die dann auf einen Schlag in die GUI-Liste übertragen, und dann von der GUI abgeholt und gelöscht werden. Zentral ist aber die doppelte Datenhaltung um GUI und Thread nicht zu stark aufeinander warten zu lassen, und das Signaling via Windows Message. (Gerne packe ich auch noch die self-Referenz des sendenden Threads in wParam oder lParam, damit das Formular auch gleich den richtigen Absender an der Hand hat wenn es mehrere parallele gleichtypige Threads gibt.)
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:25 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz