Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TThread.Synchronize (https://www.delphipraxis.net/173761-tthread-synchronize.html)

Der schöne Günther 14. Mär 2013 18:03

Delphi-Version: XE2

TThread.Synchronize
 
Hallo-

Ich weiß dass schätzungsweise 20% des weltweiten Internet-Traffics von Fragen zu Delphi-Threads und
Delphi-Quellcode:
Synchronize()
verursacht werden, trotzdem finde ich nicht wirklich eine Antwort:

Überall sprechen die Leute nur davon, von einem Thread aus etwas im Kontext des Haupt-Threads auszuführen. Praktisch immer um ein VCL-Element zu aktualisieren. Ich möchte aber vom Hauptthread aus eine Methode im Kontext meines TThread-Objekts aufrufen. Besser noch: Eine lokale Variable auf dem Stack eines Threads A mit Werten füllen die ein Thread B in Erfahrung bringt.

In den letzten Tagen wusste ich noch nicht einmal, dass es ein Delphi TThread-Objekt gibt. Bislang bin ich immer direkt den Weg über die WinAPI mittels CreateThread/BeginThread und kritischen Abschnitten gegangen. Jetzt dachte ich, TThread sei unheimlich komfortabel.

Ich dachte, ich kann es einfach folgendermaßen über die Bühne bringen:
Delphi-Quellcode:
TThread.Synchronize(
   meinThread,
   procedure
   begin
      lokaleVariable := getWert();
   end
);
Das klappt nicht wirklich. Oder zumindest nicht, wie ich mir das vorgestellt habe: Mit diesem Aufruf ist anscheinend keineswegs sichergestellt, dass sich
Delphi-Quellcode:
meinThread
nicht auch grade durch
Delphi-Quellcode:
getWert()
wühlt, der darin dann unterbrochen wird, und anschließend der Kram noch einmal obendrauf ausgeführt wird? Denn danach sieht es mir aus...
Spontan hätte ich jetzt erwartet, dass
Delphi-Quellcode:
TThread.Synchronize(meinThread, ...)
erst einmal so lange blockiert, bis meinThread sich schlafen gelegt hat oder wenigstens nicht selbst gerade mittendrin in getWert() steckt!

Habe ich durch TThread überhaupt etwas gewonnen? Oder muss ich trotzdem wieder auf kritische Abschnitte und Pipes zurückgreifen?

DeddyH 14. Mär 2013 18:22

AW: TThread.Synchronize
 
Synchronize wird vom TThread-Objekt aufgerufen, nicht aus dem Hauptthread heraus. Du kannst Daten zwischen den Threads z.B. mittels Events oder Messages austauschen.

stahli 14. Mär 2013 18:47

AW: TThread.Synchronize
 
Zur Syncronisation habe ich hier mal ein kleines übersichtliches Beispiel.

Der schöne Günther 14. Mär 2013 19:23

AW: TThread.Synchronize
 
Hallo -

Ich entschuldige mich für den Sauhaufen an Buchstaben, ich war schon halb durch die Tür. Deswegen hat man wahrscheinlich nicht ganz verstanden, was meine Frage ist. Hoffentlich ist es jetzt klarer.

Sir Rufo 14. Mär 2013 20:13

AW: TThread.Synchronize
 
Wichtig ist hierbei auch der Blick in die Dokumentation TThread.Synchronize.
Zitat:

Zitat von TThread.Synchronize
Führt einen Methodenaufruf im Haupt-Thread aus.

Also egal von wo auch immer das ausgeführt wird, es wird synchron zum Hauptthread ausgeführt.

Greift dabei auf etwas zu was von einem anderen Threadkontext auch benutzt werden kann, dann kann es knallen.

Also entweder alles immer über den Hauptthread synchronisieren (ja, ist doof) oder die Zugriffe mit Delphi-Referenz durchsuchenTCriticalSection sichern.

Erzähl doch mal, was die Threads machen sollen, evtl. kann man das auch mit Bei Google suchenOmniThreadLibrary stressfreier lösen

Furtbichler 15. Mär 2013 06:58

AW: TThread.Synchronize
 
[QUOTE=Der schöne Günther;1207437
Habe ich durch TThread überhaupt etwas gewonnen? Oder muss ich trotzdem wieder auf kritische Abschnitte und Pipes zurückgreifen?[/QUOTE] Na, die Klasse kapselt die Thread-Funktionalität. Du definierst das Verhalten des Threads, also:
1. Wie bzw. womit wird er initialisiert? (Konstruktor)
2. Was soll er im Hintergrund machen? (Execute-Methode)
3. Was soll passieren, wenn er fertig ist. (OnTerminate-Event)

Bei Punkt 2 kommt dann die Synchronize-Geschichte ins Spiel. Hiermit kannst Du z.B. Statusanzeigen umsetzen. Wichtig ist hier, das Synchronize so lange wartet, bis der Hauptthread sich drum kümmern kann. Es geht also Zeit flöten.

Der Datenaustausch zwischen dem Thread und anderen Threads erfolgt meist über Eigenschaften, deren Setter und Getter mit kritischen Abschnitten (CS) vor konkgruenten Zugriffen schützt.

Ein Thread kann einem anderen Thread auch über Messages oder Events mitteilen, das irgend etwas passiert ist (ein Milestone, Zwischenergebnis o.ä.). Der andere Thread holt sich dann die Daten ab (über CS gesichert) und verarbeitet die dann weiter.

Der schöne Günther 15. Mär 2013 07:37

AW: TThread.Synchronize
 
Vielen Dank für die Antworten! :)

Zitat:

Zitat von Sir Rufo (Beitrag 1207454)
Wichtig ist hierbei auch der Blick in die Dokumentation TThread.Synchronize.
Zitat:

Zitat von TThread.Synchronize
Führt einen Methodenaufruf im Haupt-Thread aus.

Also egal von wo auch immer das ausgeführt wird, es wird synchron zum Hauptthread ausgeführt.

Wenig später heißt es jedoch:
Zitat:

Hinweis: Wenn Sie die statische Version der Methode Synchronize mit nil/NULL als der erste Parameter verwenden, wird die von AMethod referenzierte Methode im Haupt-Thread synchronisiert.
Das hatte ich bislang so interpretiert, als könnte ich mit der gleichnamigen Klassenmethode angeben, von welchem Thread aus der Aufruf tatsächlich stattfindet. Denn wozu gebe ich einen Thread sonst überhaupt als Parameter an?

Zitat:

Zitat von Furtbichler (Beitrag 1207464)
Wichtig ist hier, das Synchronize so lange wartet, bis der Hauptthread sich drum kümmern kann. Es geht also Zeit flöten.

Gut (und beruhigend) zu wissen. Aber gerade hier beschleicht mich jetzt das Gefühl, dass ich meinen TThread noch mit irgendwas hätte ausstatten müssen, um darauf überhaupt (und auch wo) zu reagieren - Eine Art
Delphi-Quellcode:
kümmereDichUmSynchronize-AufrufeVonAnderenThreads()
.


Um kritische Abschnitte gibt es dann wohl wieder keinen Weg drum herum, ich möchte nicht, dass die Funktion "von außen" aufgerufen/angefordert wird, wenn der Thread selbst auch gerade in dieser Funktion wühlt. Jetzt bin ich mal gespannt, was
Delphi-Quellcode:
TCriticalSection
bereithält...

Sir Rufo 15. Mär 2013 07:48

AW: TThread.Synchronize
 
Was soll Delphi-Referenz durchsuchenTCriticalSection schon bereithalten?

Betreten oder Versuchen zu betreten, Verlassen that's all ;)

Der schöne Günther 15. Mär 2013 08:05

AW: TThread.Synchronize
 
Und es funktioniert sogar, der Tag ist gerettet.

Im Endeffekt bin ich zwar immer noch etwas ratlos, was für konkrete Vorteile es mir bringt, nicht direkt über die WinAPI zu gehen, aber das wird sich sicher noch zeigen. :thumb:

Medium 15. Mär 2013 08:33

AW: TThread.Synchronize
 
Ich bin von Synchronize mittlerweile ganz weg. Wenn ich im Thread API Ressourcen brauche erstelle ich sie mir dort (nicht als Kompo auf dem Formular z.B.), Threads teilen sich nur via PostMessage mit, und haben Properties deren Getter und Setter mit jeweiligen Critical Sections versehen sind. Zwar wimmelt es in der Thread-Methode je nach Fall von
Delphi-Quellcode:
CS.Enter; try ... finally CS.Leave; end;
, aber so muss das Hauptprogramm nachher nicht mehr machen, als die Messages zu emfangen und kann einfach so auf den Feldern des Threads agieren. (Üblicherweise dann Work-Queues und erweiterte Status-Objekte o.ä.)

Ist etwas mehr Tipperei, aber seit ich das so durchziehe habe ich nie wieder einen Thread gegen die Wand fahren lassen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:01 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz