Entwickler-Ecke
Sonstiges (Delphi) - MyThread.Terminate und FreeAndNil(MyThread) ?
crowley - Fr 23.06.06 10:33
Titel: MyThread.Terminate und FreeAndNil(MyThread) ?
Hallöli
ich habe ein irritierendes Problem: Also... ich möchte in einem eigenen Thread ein Form anzeigen, dass mir mittels Fortschrittsbalken anzeigt, dass "etwas" passiert... Schlussendlich ist es eine Progressbar, die auf und ab läuft. Prinzipiell funktioniert das auch hervorragend. Jetzt habe ich aber Probleme im destructor. Wenn ich im Hauptprogramm schreibe
Delphi-Quelltext
1: 2:
| MyThread.Terminate; MyThread := nil; |
habe ich keinerlei Problem. Wenn ich allerdings - in welcher Form auch immer - den destructor aufrufe, dann hängt sich die Anwendung auf...
Delphi-Quelltext
1: 2:
| MyThread.Terminate; FreeAndNil(MyThread); |
Hier zuerst mal der Quellcode meines Thread- Objektes:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80:
| unit GnProgressThread;
interface
uses Classes, GnProgressForm;
type TProgressThread = class(TThread) private FProgForm : TProgressForm;
procedure ShowProgress; public constructor Create(CreateSuspended: Boolean); destructor Destroy; override;
procedure Execute; override; end;
implementation
uses Forms, SysUtils;
constructor TProgressThread.Create(CreateSuspended: Boolean); begin inherited;
FreeOnTerminate := true; end;
destructor TProgressThread.Destroy; begin if not Terminated then begin Terminate; if Suspended then Resume;
WaitFor; end;
if Assigned(FProgForm) then begin FProgForm.Close; FreeAndNil(FProgForm); end;
inherited Destroy; end;
procedure TProgressThread.Execute; begin Synchronize(ShowProgress); end;
procedure TProgressThread.ShowProgress; begin FProgForm := TProgressForm.Create(nil);
try FProgForm.Show;
while not Terminated do begin if FProgForm.ProgressBar.Position < FProgForm.ProgressBar.Max then FProgForm.ProgressBar.Position := FProgForm.ProgressBar.Position + 1 else FProgForm.ProgressBar.Position := FProgForm.ProgressBar.Min + 1;
Sleep(20); Application.ProcessMessages; end; finally FProgForm.Close; FreeAndNil(FProgForm); end; end;
end. |
Wenn der destructor so aufgerufen wird, bleibt er an dem WaitFor hängen... der Verzicht auf FreeOnTerminate machte keinen Unterschied...
In meinem MainForm habe ich einen Button mit folgenden Code integriert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TTestMainForm.Button1Click(Sender: TObject); begin if not Assigned(FThread) then begin FThread := TProgressThread.Create(false); end else begin FThread.Terminate; FThread := nil; end; end; |
Hat da jemand eine Idee, was da verkehrt ist ?
C.
digi_c - Fr 23.06.06 15:49
Ich habe noch nichts groß mit Threads gemacht aber die VCL und die Forms sind doch nicht threadsave also musst du vielleicht mit Critical Sections arbeiten?
Grendel - Fr 23.06.06 16:02
Du musst nach dem Aufruf von "Terminate" noch mit "WaitFor" auf die Beendigung des Thread warten. Terminate beendet den Thread nicht sofort, sondern setzt die Eigenschaft "Terminated" auf True und signalisiert dem Thread dadurch, daß er sich demnächst doch beenden möge. WaitFor kehrt dann zurück, wenn der Thread wirklich durchgelaufen ist.
Danach sollte Free() auch keinen Fehler mehr werfen.
Bis neulich ...
edit: Hab Blödsinn geschrieben. Wenn Du FreeOnTerminate auf True setzt darfts Du natürlich nicht selber versuchen den Thread freizugeben. Nach dem Aufruf von Terminate und WaitFor genügt es, der Variablen einfach nil zuzuweisen. Mit Free bzw. FreeAndNil versuchst Du ja sonst ein Objekt freizugeben, daß garnicht mehr existiert.
Nur wenn FreeOnTerminate False ist muss Du selber Free aufrufen.
crowley - Mo 26.06.06 08:46
@Grendel... das Problem besteht im WaitFor... an dieser Stelle bleibt das Programm hängen... und ich habe keine Ahnung warum... *himpf*... ich habe das ganze mit FreeOnTerminate und auch ohne getestet... es macht keinen Unterschied... *seufz*
@digi_c... Wenn ich den Zugriff auf die VCL im Synchronize mache, brauche ich keine CriticalSections... das ist dann darin schon ausreichend gekapselt...
Grendel - Mo 26.06.06 09:20
Du darfst das WaitFor nicht innerhalb des Threads aufrufen. Schmeiß den ganzen Kram aus dem destructor des Threads:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| if not Terminated then begin Terminate; if Suspended then Resume;
WaitFor; end; |
Um den Thread zu Beenden rufst Du dann folgendes auf:
Delphi-Quelltext
1: 2: 3: 4:
| FThread.Terminate(); FThread.WaitFor(); FThread.Free(); FThread := nil; |
Bis neulich ...
crowley - Mo 26.06.06 09:29
werd ich mal versuchen, danke dir ;)
hatte mich bei der implementation an den destructor in der (originalen) TThread-Klasse gehalten... da steht das WaitFor auch im destructor *gg*
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!