Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   2 Threads starten/pausieren... (https://www.delphipraxis.net/196762-2-threads-starten-pausieren.html)

jaenicke 18. Jun 2018 10:57

AW: 2 Threads starten/pausieren...
 
Zitat:

Zitat von MicMic (Beitrag 1405062)
Den 0-5000 Thread erstelle in meinem OnCreate von der Form und setzte "Thread1.FreeOnTerminate := true;".
"Thread1.Start" kommt an einer anderen Stelle zum Einsatz.

Wenn du FreeOnTerminate setzt, darfst du den TThread nicht in eine Variable (Thread1) speichern. Denn da du nicht weißt wann dieser freigegeben wird, darfst du auch nicht mehr darauf zugreifen.

Wenn du den Thread später noch ansprechen möchtest, darfst du FreeOnTerminate nicht setzen.

MicMic 18. Jun 2018 11:09

AW: 2 Threads starten/pausieren...
 
Zitat:

Zitat von jaenicke (Beitrag 1405065)
Zitat:

Zitat von MicMic (Beitrag 1405062)
Den 0-5000 Thread erstelle in meinem OnCreate von der Form und setzte "Thread1.FreeOnTerminate := true;".
"Thread1.Start" kommt an einer anderen Stelle zum Einsatz.

Wenn du FreeOnTerminate setzt, darfst du den TThread nicht in eine Variable (Thread1) speichern. Denn da du nicht weißt wann dieser freigegeben wird, darfst du auch nicht mehr darauf zugreifen.

Wenn du den Thread später noch ansprechen möchtest, darfst du FreeOnTerminate nicht setzen.

Meinst du, ich darf nicht mit "If Thread1.Terminated = False Then" prüfen, ob der noch läuft? Ich könnte ja eine Globale Variable setzen wenn der Thread1 fertig ist, also die Repeat/Until Schleife fertig ist. (Thread1fertig=true). So wäre es besser oder?

sko1 19. Jun 2018 07:51

AW: 2 Threads starten/pausieren...
 
Zitat:

Wenn der zweite Thread gestartet wird, soll sich der erste Thread kurz schlafen legen, also die For-Schleife soll auch pause machen
Ich verstehe diesen Ansatz nicht ganz, das widerspricht doch dem Sinn eines Threads!
Denn der läuft im Hintergrund und blockiert damit den Haupt-Thread nicht mehr mit zeitaufwändigen Schleifen.
Warum soll der nun pausiert werden wenn ein weiterer Thread gestartet wird?

Ciao
Stefan

OlafSt 19. Jun 2018 08:17

AW: 2 Threads starten/pausieren...
 
Warum so kompliziert.

Gib doch den einzelnen Datenelementen ein Flag "Hab ich schon" mit. Das wird gesetzt, sobald der Thread das Element verarbeitet hat. Außerdem gibst dem Thread mit, von wo bis wo er arbeiten soll (Standard 0 bis Ende). Dann lass den Thread laufen.

Will der User nun plötzlich die Elemente 200-800 verarbeitet haben, gibst dem Thread einfach diese beiden Werte an. Der Thread verarbeitet den laufenden datensatz noch ab und kümmert sich dann um die vorgegebene Range. Durch das markieren mit "Hab ich schon" werden die ja auch kein zweites Mal angefaßt. Hat der Thread seine Range durch (also 200-800 abgearbeitet), gehts einfach wieder von vorn los mit 0-Ende. Durch das "Hab ich schon" arbeitet er dann von ganz allein die ganze Arie ab - selbst wenn der User plötzlich noch 1000-1600 sehen will.

Alles in einem Thread, ohne kompliziertes Anhalten/Weiterlaufen/Synchronisieren.

jaenicke 19. Jun 2018 12:24

AW: 2 Threads starten/pausieren...
 
Zitat:

Zitat von OlafSt (Beitrag 1405180)
Gib doch den einzelnen Datenelementen ein Flag "Hab ich schon" mit.

Das ist ja genau die Idee hinter der von mir vorgeschlagenen Queue, nur dass man damit die abzuarbeitenden Daten besser steuern kann als mit ein paar Flags.

Es kommt natürlich immer darauf an was man genau braucht, das kann man von außen nicht genau sagen.

Dennis07 19. Jun 2018 12:27

AW: 2 Threads starten/pausieren...
 
Zitat:

Zitat von jaenicke (Beitrag 1405065)
Wenn du FreeOnTerminate setzt, darfst du den TThread nicht in eine Variable (Thread1) speichern. Denn da du nicht weißt wann dieser freigegeben wird, darfst du auch nicht mehr darauf zugreifen.

Wenn du den Thread später noch ansprechen möchtest, darfst du FreeOnTerminate nicht setzen.

Wiebitte? Wie soll er denn bitte erzeugen,
Delphi-Quellcode:
FreeOnTerminate
setzen und starten, ohne den Thread zwischenzuspeichern? Das ginge, wenn überhaupt, nur noch entweder im
Delphi-Quellcode:
Execute
(was unsauber wäre) oder mit einem
Delphi-Quellcode:
with
(ebenso). Prinzipiell kannst du ihn ja in so vielen Variablen speichern, wie du lustig bist. Du darfst/solltest nur nach dem Starten der Ausführung nicht mehr auf mehr auf das Objekt ohne
Delphi-Quellcode:
try
zugreifen, sofern
Delphi-Quellcode:
FreeOnTerminate
gesetzt wurde. Davor jedoch kannst du so viel an dem Ding rumspielen wie es dir danach verlangt.

himitsu 19. Jun 2018 13:23

AW: 2 Threads starten/pausieren...
 
Sorry, aber TRY ...

Man darf NIEMALS wieder darauf zugreifen, sobald der Thread einmal gestartet wurde, egal wo.

Ausnahme: Der Thread setzt diese Variable auf NIL, bevor er freigegeben wird.
Zugriffe auf diese Variable aber auch nur noch abgesichert, also z.B. innerhalb einer CriticalSection.

jaenicke 19. Jun 2018 13:52

AW: 2 Threads starten/pausieren...
 
Zitat:

Zitat von Dennis07 (Beitrag 1405225)
Wiebitte? Wie soll er denn bitte erzeugen,
Delphi-Quellcode:
FreeOnTerminate
setzen und starten, ohne den Thread zwischenzuspeichern?

Warum sollte man denn einen solchen run-and-forget Thread suspended erzeugen?!? Der bekommt alle notwendigen Parameter und legt sofort los.

(Ich sehe generell keinen Sinn darin suspended zu erzeugen, egal was für ein Thread das ist. Entweder man braucht den Thread jetzt, dann kann er auch gleich loslegen oder man braucht ihn noch nicht, dann braucht man ihn auch noch nicht erzeugen.)

Aber für genau diesen Zweck, ihn nach dem Erzeugen zu starten, kann man eine solche Variable natürlich benutzen. Aber eben danach nicht mehr.

MicMic 22. Jun 2018 00:17

AW: 2 Threads starten/pausieren...
 
Hallo,
da sind wir wohl etwas durcheinander gekommen. Oder ich :)
Also ich habe einen Thread der mit einer Repeat/Until-Schleife eine reihe von Zahlen durchgeht. Beispielsweise 0-5000. Den erstelle ich inaktiv in meinem Form-Create und mit „FreeOnTerminate = True“ (damit er sich selbst freigibt, wenn fertig). Inzwischen sind es zwei Threads davon, weil es auch zwei Datenhälften gibt, die wechselnd verarbeiten werden sollen. Passt so besser. Die beiden Threads nenne ich jetzt mal die Hauptthreads. Sie werden an einer passenden Stelle im Programm gestartet und kommen auch nur 1x zum starten.

Nun greift beispielsweise der Benutzer während die beiden Hauptthreads laufen ein und es wird dann von einer Datenhälfte ein Paket benötigt. (z.b. 3000-4000). Damit alles schneller geht, sollen nun die beiden Hauptthreads Pause machen.

Ich habe das nun so gelöst, dass es wiederum zwei weitere Threads gibt, die für die Aktion des Benutzers zuständig ist. Die nenne ich jetzt mal UserThreads. Die sind jedenfalls noch nicht erstellt, sondern werden erst erstellt, wenn der Benutzer die Aktion wählt, sprich das Paket von 3000-4000 als erstes geladen werden soll. Passiert so etwas, dann wird erst mal geprüft ob der Hauptthread für die richtige Datenhälfte überhaupt noch läuft. Ist er nämlich fertig, dann brauch man auch kein Userthread mehr. Diese Prüfung hatte ich mit einem „if .Terminated“ geprüft aber da war ich mir nicht so sicher, da diese Hauptthreads sich selber freigeben und ob man dann mit diesem „Termitated“ darauf noch zugreifen darf, ist mir nicht so ganz klar. Es geht zwar aber ich habe lieber eine globale Variable dafür eingesetzt. Die Benutzer-Aktion (1 von 2) schaut jedenfalls so aus:
Code:
If HThread1Finish = False Then
Begin
  UserThread1.free;
  UserThread1 := TUserThread1.Create(true);
  UserThread1.FreeOnTerminate := false;
  Userthread1.Priority := tpTimeCritical;
  UserThread1.iv := startzahl // z.B. 3000
  UserThread1.ib := enddzahl // z.B. 4000
  UserThread1.Start;
End;
Also beim ersten Mal ist ein „.free“ irgendwie nutzlos aber für weitere Aktionen ist hier dafür der beste Platz. Es macht wohl nichts aus, wenn ein Thread freigegeben werden soll, der gar nicht existiert. Bei einer 2. Aktion vom Benutzer wird er jedenfalls freigegeben und darauf wieder erstellt. So starte ich jedenfalls meine UserThreads. Hier bei den UserThreads habe ich kein „ FreeOnTerminate=True“ gewählt, da sie auch durch eine neue Aktion vom Benutzer abgebrochen werden sollen. Wegen „Priority“… ich muss da noch mal schauen ob das was bringt. In der Execute von UserThread1 (auch im anderen UserThread2) setze ich noch eine globale Varibale „ThreadsPause“ auf „True“, damit die beiden Hauptthreads nicht in der Repeat/Until Schleife weiter hoch zählen. Ist UserThread1 fertig, wird die Variable „ThreadsPause“ wieder auf „False“ gesetzt und die Hauptthreads laufen weiter bzw. sie laufen ja die ganze Zeit aber die Zählervariable dort, wird wieder weiter hochgezählt. Nach der letzten Benutzer-Aktion bleiben ja immer noch zwei UserThreads im Speicher. In meinem Form Destroy gebe ich dann noch die beiden UserThreads frei. So funktioniert das ganze eigentlich recht gut. Natürlich habe ich bei meinen Daten auch ein „hab ich schon“ also als „User[zählervariable].Nummer“ festgelegt. Die Nummer steht auf „-1“ und wenn die Daten verarbeitet wurden, wird diese auf einen anderen Wert (größer als -1) festgelegt. Also wenn der Benutzer ein Paket von 3000-4000 haben will und der Hauptthread ist hier noch nicht angekommen (wird später auf diesen Zahlenbereich kommen), dann ist dies nicht so schlimm. Ich prüfe ja auf den Wert „-1“ und nur dann kommen die rechenintensiven Befehle zum Einsatz. Das Ganze wollte ich ja nur mit einem Thread lösen aber die ganzen Variablen zu setzen (außerhalb) sind schwer im Thread zu prüfen, da der Thread ja läuft und immer wo anders ist, im Execute Bereich (mal Zeile 4, dann 7 und mal Zeile 13). Da macht es sich schwer, ein 0-5000 abzubrechen, dann 3000-4000 durchzugehen, wobei durch einen neuen Abbruch das ganze nur bis 3580 gegangen ist, weil der Benutzer ja schon wieder neue 200-1200 haben will. Dies mit Variablen so zu prüfen, dass sich nichts in die quere kommt, ist echt schwer. Bestimmt gibt es da Lösungen/Befehle etc. denn es gibt ja nicht nur „Execute“. Es sind ja auch meine ersten Erfahrungen mit Threads und so wie ich es jetzt habe, gefällt es mir natürlich dann… weils halt geht :)

Ich hoffe es ist nun verständlich wie ich so meine Threads einsetze und zu welchem Zweck. Ich fülle Daten Records mit Werten, die dann zur Ansicht kommen. 2-3 Befehle (um mein Daten Record zu füllen) kosten dann etwas Zeit und damit der Benutzer auf diese Ansicht nicht warten muss, brauche ich dann diese Threads… die sicherlich besser gelöst werden können aber ich halt noch kein Durchblick dazu habe. :)

Michael

Rollo62 22. Jun 2018 08:44

AW: 2 Threads starten/pausieren...
 
Klingt kompliziert, habs jetzt nicht komplett nachvollzogen was du machst ...

Ich würde einfach zwei Threads über Events steuerbar machen, so in der Art, aber die Setter/Getter der Zugriffs-Properties noch sicherheitshalber in TCriticalSections verpacken.
Dann könntest du die Threads intern immer laufen lassen, und ja nach Guste über die Events stillegen oder freischalten.

Dann braucht man kein "Terminate" (nur am Programende, und keine globalen Variablen.

Rollo


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:33 Uhr.
Seite 2 von 2     12   

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