Autor Beitrag
Holgerwa
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 19.06.05 16:19 
Ein Thread beendet sich nach getaner Arbeit selbst. ;)
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: 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:
ausblenden 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);
//  Terminate;
end;

Den Thread erstelle ich so:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  MeinThread := TMeinThread.Create (true);
  // ... hier werden noch ein paar Variablen für den Thread gesetzt
  MeinThread.Resume; // jetzt läuft er, und die Caption des Hauptfensters ändert sich

  while not MeinThread.Terminated do
    Application.ProcessMessages;
  // hier kommt er nie an

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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 19.06.05 16:50 
:lol: Da hab ich dich falsch verstanden. ;) Du benutzt also die Komponente TThread, ja? Hat das einen bestimmten Grund? Wieso schreibst du nicht einfach das da:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function MyThread: Integer;
var i: integer;
begin
  for i := 0 to 1000 do
    Hauptform.Caption := IntToStr (i);
  result := 0;
end;


Und "erstellst" den Thread so:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
  var
  ID: Cardinal;
  // ... hier werden noch ein paar Variablen für den Thread gesetzt
  BeginThread(nil, 0, @MyThread, nil, 0, ID)
Holgerwa Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: 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



BeitragVerfasst: 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:
ausblenden Delphi-Quelltext
1:
type TThreadFunc = function(Parameter: Pointer): Integer;					


Alles weitere in meinem Thread-Tutorial: delphitutorials.luckie-online.de
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: 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



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 19.06.05 20:43 
user profile iconLuckie hat folgendes geschrieben:
2. @WeBsPaCe: Die Theead-Funktion ist wie folögt definiert:
ausblenden Delphi-Quelltext
1:
type TThreadFunc = function(Parameter: Pointer): Integer;					

Wieso soll man die so schreiben sollen? :gruebel:
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 19.06.05 20:56 
user profile iconalzaimar 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? :eyes:
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: 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
ausblenden 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



BeitragVerfasst: Mo 20.06.05 14:22 
user profile iconalzaimar 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mo 20.06.05 15:33 
user profile iconLossy 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 :oops:
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: 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. ;-)

ausblenden Delphi-Quelltext
1:
2:
3:
  while not MeinThread.Terminated do
    Application.ProcessMessages;
  // hier kommt er nie an


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.