| Autor |
Beitrag |
Holgerwa
      
Beiträge: 325
WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
|
Verfasst: So 19.06.05 16:17
Hallo,
ich möchte eine Aktion durchführen, die ein bischen länger dauert, und während dessen im Hauptprogramm etwas anzeigen (Status).
Dafür habe ich einen Thread, der die Aktion durchführt, und auch den Status aktualisiert. Das Hauptprogramm wartet, bis der Thread beendet wurde (while not Thread.Terminated...).
Wie aber beendet sich ein Thread selbst, wenn er fertig ist?
Im Moment rufe ich am Ende von .Execute einfach Terminate auf, aber ich habe keine Ahnung, ob das so gemacht werden sollte, oder ob das ein Fehler ist (auch wenn es keine direkte Fehlermeldung gibt). Ohne das Terminate läuft der Thread einfach weiter, obwohl Execute fertig ist, und braucht auch weiterhin 100% der Rechenzeit.
Holger
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: So 19.06.05 16:19
Ein Thread beendet sich nach getaner Arbeit selbst. 
|
|
Holgerwa 
      
Beiträge: 325
WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
|
Verfasst: So 19.06.05 16:28
Hallo,
dann mach ich etwas falsch, hier ein einfacher Code, der zum Test mal die Caption des Hauptfensters verändert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| procedure TMeinThread.Execute; var i: integer; begin for i := 0 to 1000 do Hauptform.Caption := IntToStr (i); end; |
Den Thread erstelle ich so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| MeinThread := TMeinThread.Create (true); MeinThread.Resume; while not MeinThread.Terminated do Application.ProcessMessages; |
Nachdem er bis 1000 gezählt hat, passiert nichts mehr, und der Task-Manager zeigt mir eine CPU-Auslastung von 100% an. Ich weiß zwar nicht, was er macht, aber der Thread scheint noch zu laufen, weil Terminated noch nicht true ist.
Wenn ich das Terminate am Ende von Execute ausführe, scheint er ordnungsgemäß zu beenden.
Wo liegt hier mein Fehler?
Danke!
Holger
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: So 19.06.05 16:50
|
|
Holgerwa 
      
Beiträge: 325
WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
|
Verfasst: So 19.06.05 17:05
Hallo,
danke für die Antwort, ich versuch das gleich mal.
Gibt es denn einen Nachteil, wenn ich TThread verwende? Ich denke mir immer, wenn die Jungs von Borland uns schon solche Sachen zur Verfügung stellen, dann sollten wir sie auch verwenden
Hier mit BeginThread muß ich wohl meine Parameter für den Thread irgendwie als Pointer übergeben, was ja mit TThread schön einfach ist.
Holger
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: So 19.06.05 17:25
Also grad bei so kleinen Sachen, wie dem da, bietet sich BeginThread an.  Die "grafische" Komponente ist eben für Einsteiger viel einfacher zu handhaben, wie so ein Befehl mit so vielen Parameter, wie du selbst sagst. 
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 19.06.05 19:09
1. Griefe nie innerhalb einen Threads der mit TThread erstellt wurde außerhalb der Methode Synchronize auf ein Formular zu.
2. @WeBsPaCe: Die Theead-Funktion ist wie folögt definiert:
Delphi-Quelltext 1:
| type TThreadFunc = function(Parameter: Pointer): Integer; |
Alles weitere in meinem Thread-Tutorial: delphitutorials.luckie-online.de
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: So 19.06.05 19:21
Ich dachte, gerade (und nur) bei D6 darf man *nicht* die Synchronize-Methode benutzen, weil sonst der Prozess 'hängt'...
|
|
Holgerwa 
      
Beiträge: 325
WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
|
Verfasst: So 19.06.05 19:28
Hallo,
@Luckie: Danke für das Tutorial, SEHR interessant
@WeBsPaCe: Jetzt funktioniert es erstmal, aber das muß ich alles noch besser verstehen -> Luckie-Tutorial kommt da gerade recht!
@alzaimar: im Luckie-Tutorial steht, daß alle Zugriffe auf VCL-Komponenten über Synchronize laufen sollen, damit nicht mehrere Threads gleichzeitig auf die gleichen VCL-Funktionen zugreifen.
Danke Euch allen!
Holger
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 19.06.05 19:29
Logisch 'hängt' der Thread, weil in dem Moment, wo Synchronize aufgerufen wird, der Haupthread seinen Code ausführt und der 'Arbeitsthtread' so lange pausiert. Aber wenn du mit der VCL-Thread-Klasse arbeitest hast du keine andere Möglichkeit der Synchronisation bzw. wird diese von Borland empfohlen.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: So 19.06.05 20:04
@HolgerWa: Na, dann irrt Luckie hier, soll ja vorkommen. Mein D6 Enterprise mit allen SP hängt, gerade *weil* ich Synchronize aufrufe. Alle anderen Delphi-Versionen sind davon wohl nicht betroffen. Aber D6 eben, sollte bekannt sein...
@Luckie: Nee, schon klar, aber D6 hat hier eine Macke. Synchronize klappt eben nicht. Noch schlimmer: Man *darf* Synchronize nicht benutzen, weil dann der Prozess (=EXE) hängt. Und zwar richtig. Also muss man überall im Code mit dämlichen $IFDEF D6$ etc rumhantieren, was wirklich nervig ist.
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: So 19.06.05 20:43
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: So 19.06.05 20:50
Damit BeginThread damit anständig arbeiten kann bzw. das nicht dazu führt, das dein Programm unkontrolliert abschmiert.
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: So 19.06.05 20:56
alzaimar hat folgendes geschrieben: | | Damit BeginThread damit anständig arbeiten kann bzw. das nicht dazu führt, das dein Programm unkontrolliert abschmiert. |
Und bitte warum soll das passieren? 
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: So 19.06.05 21:10
Beginthread geht doch davon aus, das genau ein 4 Byte Wert auf den Stack geschoben wird und ein 4-Byte Resultat anschließend dadrauf steht. Die Aufrufkonvention in Delphi ist doch aber so, das die aufgerufene Routine für die Stackverwaltung zuständig ist. Also müssen sich Aufrufer und Aufgerufender einig sein.
In C ist das wohl anders, deshalb kann man auch Perversitäten wie variable Parameteranzahl programmieren: ein printf ist leicht in C zu implementieren, in Delphi geht das nicht (wg. der Optionalen Parameter).
Natürlich kannst du die Thread.Routine auch als Function (foo : Integer) : Integer
definieren oder
Delphi-Quelltext 1:
| Function (Var Bar : TBigStuff) : Integer |
Aber das Ergebnis (=Anzahl der Bytes auf dem Stack) sind die Gleichen...
Korrigier mich, wenn ich falsch liege (is Alles schon länger her, und mit meinem Altwissen lag ich schon manchmal daneben...)
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 20.06.05 14:22
alzaimar hat folgendes geschrieben: |
@Luckie: Nee, schon klar, aber D6 hat hier eine Macke. Synchronize klappt eben nicht. Noch schlimmer: Man *darf* Synchronize nicht benutzen, weil dann der Prozess (=EXE) hängt. Und zwar richtig. Also muss man überall im Code mit dämlichen $IFDEF D6$ etc rumhantieren, was wirklich nervig ist. |
Das höre ich jetzt zum ersten mal. Wo hast du denn das her? Und wie soll man denn sonst mit dem Hauptthread synchronisieren?
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Mo 20.06.05 14:51
Also wenn es das ist wofür ich es halte, dann weiß ich was Alzaimer meint. Ich habe so ein "hängen" schon mal erlebt. Aber ehrlich gesagt war das eine sehr schlechte und äußerst hirnrissige Threadimplementationen. Dort wurde ein OpenGL "Renderthread" "implementiert" (doppelter Sarkasmus beabsichtig), der nichts anderes gemacht hat als eine Renderschleife gekappselt die alles Synchronized aufegrufen hat. Also Initialisieren, Rendern und Deinitialisieren. Ist ja richtig muss alles aus einem Thread geschehen aber das war so klever gestaltet, dass sich der Vorteil des Threads bei 0,00 hielt. Aber an der Stelle hat der Thread an sich die Arbarbeitung von Windowsmessages beeinträchtigt. Und wäre ich VCL ich hätte auch gestreickt.
Ich persönlich habe jahre lang schon mit D6 gearbeitet und reichlich Threads programmiert und wenn die auch nur ansatzweise sinnvoll durchdacht waren gab es nie solche Probleme. Das einzigste was es höchstens gab waren deadlocks und da ist man dann selber dran schuld.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mo 20.06.05 15:33
Lossy eX hat folgendes geschrieben: | | Ich persönlich habe jahrelang schon mit D6 gearbeitet und reichlich Threads programmiert und wenn die auch nur ansatzweise sinnvoll durchdacht waren gab es nie solche Probleme. |
Und immer wenn ich dieses Synchronize bei D6 in die Hand genommen habe, hing die Applikation. Jetzt, wo ich mit einer Demo brillieren wollte, klappts natürlich mit Synchronize.... Kein Wunder, ich hab seit vorgestern einen neuen PC und musste Delphi no raufspielen inklusive aller Updates. Obwohl ich vorher auch schon Alle hatte, fehlte der bugfix fürs Synchronize... Laut Guhgel betraf das Delphi 6.0 ("Synchronize Delphi 6"). Egal, jetzt gehts dann doch 
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Mo 20.06.05 15:52
Das ist natürlich sehr verdächtig. Habe ja auch zu erst ohne Updates gearbeitet und dann nach und nach kamen die ja. Aber egal, wenns jetzt geht.
@Topic:
Ich weiß ja nicht ob noch bedarf besteht.
Delphi-Quelltext 1: 2: 3:
| while not MeinThread.Terminated do Application.ProcessMessages; |
Das ist die wohl schlechteste Alternative auf das Ende eines Threads zu warten. Dann hättest du dir wohl den Thread auch gleich sparen können. Ich würde da eher vorschlagen, dass du lediglich den Thread startest und evtl diverse Schaltflächen deaktivierst. Und wenn der Thread dann mit seiner Arbeit fertig ist wird das OnTerminate evevnt ausgelöst. Darin kannst du dann ja wiederum die Schaltflächen wieder aktivieren. Hat den Vorteil, dass deine Anwendung nicht mit 100% CPU Last auf das Ende des Threads wartet sondern in der Zwischenzeit noch andere Sachen machen könnte.
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|