![]() |
Threads verstehen...
Hallo,
in meinem anderen Thread(Thread beenden) hatte ich über unerklärliche Hänger in meinem Programm berichtet. Ich habe mal versucht den Fehler zu finden und dazu folgendes kleines Testprogramm mit dem ich dem Fehler scheinbar etwas auf die Spur gehkommen bin. Er liegt im Thread. Dazu erstmal folgende kleine Threadklasse:
Delphi-Quellcode:
Der Thread kann eigentlich immer nur die Zahl Null liefern, weil der Except-Block nicht ausgeführt wird.
unit unit2 ;
interface uses Classes,windows; type TConThread = class(TThread) private fErrCode: Integer; public constructor Create(CreateSuspended: boolean); protected procedure Execute; override; published property ErrCode: integer read fErrCode; end; implementation constructor TConThread.create(CreateSuspended: boolean); begin inherited create(CreateSuspended); freeOnTerminate:= true; fErrCode:= -1; end; procedure TConThread.Execute; begin Try fErrCode:= 0; terminate; except fErrCode:= 1; terminate; end; if Terminated then exit; end; end. Wenn ich jetzt folgendes mache:
Delphi-Quellcode:
stelle ich fest, dass ich in den allermeisten Fällen auch Null zurückbekomme, manchmal aber eben auch nicht. Ich habe bei 1000 Schleifendurchläufen meistens 1-2 oder dreimal etwas anderes bekommen nämlich 76 (woher es das nimmt ist mir schleierhaft)
procedure TForm1.Button1Click(Sender: TObject);
var i, count: Integer; begin Count:= 0; memo1.Lines.Clear; memo2.Lines.Clear; for i:= 0 to 1000 do begin aCon:= TConThread.Create(false); repeat until (aCon.ErrCode = 0) or ((aCon.ErrCode <> 0) and (aCon.ErrCode <> -1)); if (aCon.ErrCode <> 0) and (aCon.ErrCode <> -1) then begin memo2.Lines.Add(intToStr(aCon.ErrCode)); count:= count+1; end; memo1.Lines.Add(intToStr(aCon.ErrCode)); end; showMessage(intToStr(count)); end; Bei 100.000 Duchläufen hatte ich einmal 300 und einmal 305 mal die 76. Bei 1.000.000 Durchläufen dann plötzlich wieder nur 56 mal die Zahl 76. So, und jetzt kommt ihr...;) Gambit |
Re: Threads verstehen...
Hi.
Sofern die Property FreeOnTerminate gesetzt ist, wird der Speicherbereich des Threads beim Terminieren freigegeben und ggf. durch andere Programme genutzt. ;-) Setze einfach FreeOnTerminate auf false und das Problem ist gelöst! |
Re: Threads verstehen...
Du kannst im Übrigen auf die terminate; und exit; Aufrufe verzichten, da der Thread eh zu ende ist :wink:
(man macht meist while not Terminated do ... ) |
Re: Threads verstehen...
OK, habe jetzt mal FreeOnTerminate auf false gesetzt. Dann muss ich ja den Speicher wohl selbst wieder freigeben, oder?
habe das dann hier eingebaut:
Delphi-Quellcode:
Wäre das so dann OK?
procedure TForm1.Button1Click(Sender: TObject);
var i, count: Integer; begin Count:= 0; memo1.Lines.Clear; memo2.Lines.Clear; for i:= 0 to 1000 do begin aCon:= TConThread.Create(false); repeat until (aCon.ErrCode = 0) or ((aCon.ErrCode <> 0) and (aCon.ErrCode <> -1)); if (aCon.ErrCode <> 0) and (aCon.ErrCode <> -1) then begin memo2.Lines.Add(intToStr(aCon.ErrCode)); count:= count+1; end; memo1.Lines.Add(intToStr(aCon.ErrCode)); aCon.Free; // Hier gebe ich den Speicher wieder frei... end; showMessage(intToStr(count)); end; Gruß Gambit |
Re: Threads verstehen...
Hi,
[smartypants] In deinem Beispiel wartest du mit Repeat...Until auf die Beendigung der Threads. Das führt aber dazu, dass dein Programm in der ButtonClick Routine hängen bleibt, bis der Thread beendet wird - mit dem Effekt, dass Benutzereingaben nicht mehr abgearbeitet werden. Das Programm ließe sich dann im Extremfall nur noch mit dem Taskmanager beenden.[/smartypants] (Oder ist das jetzt Absicht? :? ) |
Re: Threads verstehen...
Theoretisch hast du recht, ich wüsste aber auch nicht, wie ichs anders machen sollte. Der Thread soll letztendlich dazu dienen, eine Verbindung zu einer Datenbank aufzubauen. Klappt der Verbindungsaufbau liefert die Execute-Methode den Wert 0 ansonsten den Wert 1. Ich muss aber solange warten, bis ich einen von beiden Werten erhalte, weil ich im Folgenden ja Datenbankabfragen mache und die gehen halt ohne Verbindung nicht. Eigentlich sollte der Thread aber eine von beiden Werten umgehend liefern.
Den Verbindungsaufbau will ich per Thead machen, damit nicht während des Aufbau alles einfriert und ich zB. eine kleine Warteanimation auf eine Form legen kann... |
Re: Threads verstehen...
Pack die Threads in eine Liste, dann kannst du z.B. in einem Timer prüfen, ob noch Threads laufen. Der Thread muss sich nur selbst aus der Liste austragen, wenn er seine Arbeit beendet hat.
|
Re: Threads verstehen...
hmmm, ja, könnte man so machen. Was mich wundert ist, nachdem ich den Speicher mit aCon.free freigegeben habe, kann ich immer noch aCon.ErrCode abfragen...
|
Re: Threads verstehen...
Und zwar aus dem gleichen Grund, warum du anfangs 76 statt 0 auslesen konntest.
Grüße vom marabu |
Re: Threads verstehen...
Jetzt war jemand schneller, aber trotzdem:
Du hast zwar den Speicher freigegeben, aber nicht gelöscht. Daher kannst Du den Wert lesen. Du hättest aber auch eine Zugriffsverletzung gekommen können. Übrigens kannst Du auch mit aCon.WaitFor auf die Beendigung des Threads warten. Dein Programm hat nämlich sonst 100% CPU Nutzung. Das macht die Threadausführung deutlich langsamer. Und Notebookbesitzer wundern sich, warum der Akku so schnell leer wird :-) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:38 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-2025 by Thomas Breitkreuz