Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Thread beenden durch Button clicked (https://www.delphipraxis.net/190504-thread-beenden-durch-button-clicked.html)

smmahaup 10. Okt 2016 15:59

Thread beenden durch Button clicked
 
Hallo Leute,

ich sitze gerade an einer Synchronisation von zwei Threads ( Messung und Übertragen in einen Stringgrid) und möchte eine TThread.execute schreiben und dieses mit einem Button click meiner GUI wieder beenden.

procedure TMeasThread.Execute;
begin
try
repeat
Form1.Measure; {Messung}
Synchronize(WriteToStringgrid); {übertragen der Messwerte}
until
//Button1.clicked, ich weiß es muss mit Sender irgendwie abgeglichen werden, aber nicht genau wie
except
....
end;
end;

Ich bitte um hilfe. Ich bin noch ein rechter Anfänger (also wäre ein Erklärung "for dummies" am besten :) )

mit freundlichen Grüßen

Markus

bra 10. Okt 2016 16:12

AW: Thread beenden durch Button clicked
 
Bei deinem Button rufst du Thread.Terminate auf und im Thread überprüfst du, ob das Terminated-Flag gesetzt ist und brichst dann die Verarbeitung ab.

Delphi-Quellcode:
procedure StopThread;
begin
  FThread.Terminate;
  FThread.WaitFor;
end;

procedure TMeasThread.Execute;
begin
  while not Terminated do begin
    Form1.Measure; {Messung}
    Synchronize(WriteToStringgrid); {übertragen der Messwerte}
    // was machen
  end;
end;
Dabei dürfen die einzelnen Schritte in der While-Schleife natürlich nicht ewig dauern, sonst hängt der auch bis er irgendwann wieder am Schleifenanfang ist.

p80286 10. Okt 2016 16:17

AW: Thread beenden durch Button clicked
 
Ich nehme an
Delphi-Quellcode:
FThread
ist vom Typ
Delphi-Quellcode:
TMeasThread
?
(Entschuldige die dumme Frage, aber meine Erfahrung mit Threads ist minimal)

Gruß
K-H

Jim Carrey 10. Okt 2016 16:17

AW: Thread beenden durch Button clicked
 
Ich kenne mich nicht perfekt aus.

Aber ich würde MeinThread.Free; bevorzugen.
Ich habe jetzt auch nicht die Source-Codes hier. Aber wird beim Aufruf von Free intern nicht irgendwo Terminated auf True gesetzt?
Ich jedenfalls habe mit Free; immer bessere Erfahrungen gemacht als mit Terminated.

Ok ein kleiner Test hat gezeigt:
Free setzt Terminated auf True

stahli 10. Okt 2016 16:49

AW: Thread beenden durch Button clicked
 
Hallo Markus,

herzlich willkommen erst mal :-)

Form1.Measure könnte man evtl. besser noch in dem Thread selbst unterbringen um die Messung auch noch vom Mainthread abzugrenzen.
Andernfalls müsste man diese auch noch synchronisieren und dann wäre der Thread unnötig (jedenfalls nach dem vorliegenden Beispiel).

Jim Carrey 10. Okt 2016 16:53

AW: Thread beenden durch Button clicked
 
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
 DeinThreadObject := TDeinThreadObject.Create; // Thread erzeugen (wie auch immer du das machst, falls anders)
end;
Delphi-Quellcode:
procedure TMeasThread.Execute;
begin
 while not Terminated do // solange der Thread nicht erminiert wurde, führe die Schleife aus
  begin
   Form1.Measure; {Messung}
   Synchronize(WriteToStringgrid); {übertragen der Messwerte};
  end;
end;
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
begin
 DeinThreadObject.Free; // Thread "terminieren"
end;

Aviator 10. Okt 2016 17:00

AW: Thread beenden durch Button clicked
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350388)
Delphi-Quellcode:
procedure TMeasThread.Execute;
begin
 while not Terminated do // solange der Thread nicht erminiert wurde, führe die Schleife aus
  begin
   Form1.Measure; {Messung}
   Synchronize(WriteToStringgrid); {übertragen der Messwerte};
  end;
end;

Eventuell sollte in die Schleife noch ein
Delphi-Quellcode:
Sleep(1)
rein damit der Thread die CPU nicht zu 100% auslastet.

Und wie Stahli schon schreibt, solltest du aus dem Thread nicht auf deine Form(klasse) zugreifen. Methoden funktionieren zwar, aber jenachdem was darin mit der GUI passiert, könnte es unschöne Effekte geben. Von daher lager die am Besten auch in den Thread aus. Nur deshalb machst du diesen ja.

Jim Carrey 10. Okt 2016 17:08

AW: Thread beenden durch Button clicked
 
Verständnisfrage: wie soll man dann von innerhalb des Threads das StringGrid füllen?

Mit einer ProgressBar würde ich es vielleicht so machen...
- innerhalb des Threads wird eine Variable gesetzt welche auf dem Hauptformular in einem Timer abgefragt wird und die ProgressBar setzt.
Oder so ganz und gar nicht?
Aktuell benutze ich statt des Timers einen zweiten Thread der nur dafür da ist die ProgressBar zu bedienen, insofern sich ein bestimmter Wert geändert hat.

Aber mit einem StringGrid ist das ja nicht so leicht machbar.

Aviator 10. Okt 2016 17:18

AW: Thread beenden durch Button clicked
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350391)
Verständnisfrage: wie soll man dann von innerhalb des Threads das StringGrid füllen?

Mit einer ProgressBar würde ich es vielleicht so machen...
- innerhalb des Threads wird eine Variable gesetzt welche auf dem Hauptformular in einem Timer abgefragt wird und die ProgressBar setzt.
Oder so ganz und gar nicht?
Aktuell benutze ich statt des Timers einen zweiten Thread der nur dafür da ist die ProgressBar zu bedienen, insofern sich ein bestimmter Wert geändert hat.

Aber mit einem StringGrid ist das ja nicht so leicht machbar.

Andere Frage: Wieso sollte das nicht funktionieren?

Bei einer Progessbar setzt du die Position auf einen Wert oder rufst Step() auf. Bei einem StringGrid müsstest du nur
Delphi-Quellcode:
StringGrid.Cells[0, 0] := 'String';
ausführen. Ist ja im Prinzip das Gleiche.

Nur macht man es nicht. Ich würde aus dem Thread ein Event mit Synchronize feuern, das von der MainForm abonniert wurde, und dann das StringGrid updaten.

p80286 10. Okt 2016 17:23

AW: Thread beenden durch Button clicked
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350391)
Verständnisfrage: wie soll man dann von innerhalb des Threads das StringGrid füllen?

Gar Nicht!

Du kannst z.B. in der Messung einen Ergebnissatz erstellen. Die Messung sendet an den Haupt-Thread eine Nachricht, und dieser holt dann den Ergebnissatz ab und trägt ihn in das Grid ein.
Und wenn es mehr als 1 Ergebnis gibt, dann solltest Du das z.B. mit einer Liste oder einem Array organisieren.


Gruß
K-H

stahli 10. Okt 2016 17:40

AW: Thread beenden durch Button clicked
 
Grundsätzlich kann man das Grid aus dem Thread heraus befüllen, wenn dies synchronisiert erfolgt. So lange steht halt der Thread.

Wenn man ein Zwischenergebnis schnell in eine Liste wirft, kann der Thread sofort weiter wuseln und das nächste Ergebnis holen.
Der Mainthread kann dann nach und nach ein Ergebnis aus der Liste holen und dieses darstellen.
In dem Fall muss aber die Liste gegen konkurrierende Zugriffe abgesichert werden (z.B. mit CriticalSections) damit der Thread die Liste nicht beschreiben will während der Mainthread einen Eintrag entnimmt und die Liste kürzt. Der Thread könnte dann keinen Eintrag mehr hinter die ermittelte letzte Position hängen, da die inzwischen nicht mehr existiert.

Also ist die ursprüngliche Lösung die einfachere und bessere, sofern diese keine Performanceprobleme mit sich bringt.

Luckie 11. Okt 2016 01:16

AW: Thread beenden durch Button clicked
 
Ist eigentlich niemand aufgefallen, dass man mit
Delphi-Quellcode:
Form1.Measure;
auf das VCL-Formular aus dem Thread zugreift, was man tunlichst unterlassen sollte?

smmahaup 11. Okt 2016 07:59

AW: Thread beenden durch Button clicked
 
Hallo Leute,
vielen Dank für das tolle Feedback.

Ich hatte das mit MyThreadObject.terminate schon ausprobiert. Dabei kommt mir aber eine Fehlermeldung auf 'Cannot terminate an externally thread.'

Bei MyThreadObject.free wird mir eine Access Violation angezeigt.

Ich habe mir eine 'WAIT'-Funktion in meine WriteToStringgrid - Procedure geschrieben, das sollte doch reichen?

Wäre schön wenn wir das noch lösen könnten ;)

Geda 11. Okt 2016 08:29

AW: Thread beenden durch Button clicked
 
Moin,

setze im Thread "FreeOnTerminate" auf "True" und schreibe in Deinem Main-Thread (Fenster) eine Ereignisbehandlung für "OnTerminate", in der Du z.B. eine Message ausgibst ("Thread beendet"), ein Flag setzt oder andere schöne Dinge tust, um die Beendigung des Threads mitzubekommen.

Der Thread wird mit "Terminate" zum Beenden angeregt. Die von Dir angesprochene Fehlermeldung ("extern ...") kenne ich z.B. von dem Fall, dass der Thread eigentlich schon freigegeben ist (z.B. weil das Programm beendet wird).

Hope this helps,

Geert

smmahaup 11. Okt 2016 10:39

AW: Thread beenden durch Button clicked
 
Zitat:

Zitat von Geda (Beitrag 1350435)
Moin,

setze im Thread "FreeOnTerminate" auf "True" und schreibe in Deinem Main-Thread (Fenster) eine Ereignisbehandlung für "OnTerminate", in der Du z.B. eine Message ausgibst ("Thread beendet"), ein Flag setzt oder andere schöne Dinge tust, um die Beendigung des Threads mitzubekommen.

Der Thread wird mit "Terminate" zum Beenden angeregt. Die von Dir angesprochene Fehlermeldung ("extern ...") kenne ich z.B. von dem Fall, dass der Thread eigentlich schon freigegeben ist (z.B. weil das Programm beendet wird).

Hope this helps,

Geert

Hallo Geert!

Da stellt sich mir die Frage:

OnTerminate wird doch ausgelöst, sobald die Methode Execute des Threads zurückgekehrt ist, aber bevor der Thread freigegeben wird.
Aber ich möchte ja mit der Flag des Terminates meine Schleife beenden lassen. Wenn ich das richtig verstanden habe, werde ich aber solange zurückkehren, wie mein Terminate nicht gesetzt ist.
Da bin ich mir also nicht so schlüssig, wie ich damit arbeiten soll.
Danke schonmals.

Markus

sakura 11. Okt 2016 10:44

AW: Thread beenden durch Button clicked
 
Die drei TerminateXXX:

Terminate: Methode, um den Thread zu beenden. Kann aus anderen Threads aufgerufen werden, um einen Thread dazu zu bringen, die Ausführung zu beenden.
Terminated: Eigenschaft, kann in der Execute-Methode abgefragt werden, um auf eine Terminate-Anforderung zu reagieren.
OnTerminate: Event, wird aufgerufen, wenn der Thread beendet wird.

...:cat:...

Jim Carrey 11. Okt 2016 10:53

AW: Thread beenden durch Button clicked
 
Da du dich mit Threads auskennst.

.Free, .Terminate oder beides um einen Thread zu beenden?

sakura 11. Okt 2016 11:01

AW: Thread beenden durch Button clicked
 
Zitat:

Zitat von Jim Carrey (Beitrag 1350447)
.Free, .Terminate oder beides um einen Thread zu beenden?

Wie oben schon geschrieben, würde auch ich empfehlen:
Delphi-Quellcode:
FreeOnTerminate := True;
, das mache ich meist direkt im Konstruktor, so dass es per Standard für alle Threads gilt. Dann reicht ein Aufruf an
Delphi-Quellcode:
Terminate;
, um den Thread zu beenden, auch wird dieser dann automatische freigegeben, wenn das Programm beendet wird oder dieser seine Aufgabe erfolgreich erledigt hat. Das hilft Speicherlöcher zu vermeiden.

...:cat:...


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:29 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 by Thomas Breitkreuz