Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Freigeben eines suspended Threads (https://www.delphipraxis.net/167960-freigeben-eines-suspended-threads.html)

UliBru 27. Apr 2012 09:40


Freigeben eines suspended Threads
 
Hab da mal eine Frage zu folgendem minimalen Programmcode mit einem Thread.
Hauptprogramm:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
    myThread: TmyThread;
  end;

var
  MainForm: TForm1;

implementation
{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  myThread := TmyThread.Create(true);
  myThread.FreeOnTerminate := true;
//  myThread.Start;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if (myThread <> nil) then
  begin
    if not myThread.Suspended then //Thread ist gestartet
    begin
      myThread.Terminate;
      while not myThread.Finished do
        sleep(10);
    end
    else //Thread wurde nicht gestartet
      myThread.Free;
  end;
end;
Thread:
Delphi-Quellcode:
type
  TmyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

implementation


procedure TmyThread.Execute;
begin
  while not Terminated do
  begin
    Sleep(50);
  end;
end;
Es geht dabei um die Frage was korrekterweise im FormClose stehen müsste. Wenn der Thread gestartet ist, alles ok. Wenn aber nicht, dann befindet sich der Thread bei Close im suspended-Zustand. myThread.Free bring eine Exception 'Thread Error: Das Handle ist ungültig'. Ohne myThread.Free gibt es ein Memory Leakage.

Wie kann man das Leakage vermeiden, also das Objekt korrekt freigeben?

himitsu 27. Apr 2012 10:19

AW: Freigeben eines suspended Threads
 
Delphi-Quellcode:
myThread.Terminate;
if myThread.Suspended then myThread.Start;
//falls Free nicht wartet (bin mir grade nicht sicher), dann hier warten bis Thread sich beendet hat
myThread.Free;

UliBru 27. Apr 2012 10:48

AW: Freigeben eines suspended Threads
 
Mmhh, die Lösung, den Thread zwangsweise im FormClose zu starten, finde ich irgendwie befremdlich. Wieso wird das Objekt mit Free nicht freigegeben wie jedes andere auch?

Zacherl 27. Apr 2012 10:53

AW: Freigeben eines suspended Threads
 
Wundert mich ehrlich gesagt auch, dass das Handle angeblich invalid sein soll. Die Klasse erstellt ja den Thread ganz normal per CreateThread() / BeginThread(). Auch wenn er anfangs suspended ist, darf das Handle nicht invalid sein, sonst könnte man den Thread ja überhaupt nicht mehr resumen.

Ah, lass mal das FreeOnTerminate auf false. Ich vermute hier wird irgendwie 2x versucht den Thread zu terminieren und beim 2. Versuch ist dann das Handle ungültig.

UliBru 27. Apr 2012 10:58

AW: Freigeben eines suspended Threads
 
Yep, bin da auch eben dahintergekommen. Also es klappt sauber mit
Delphi-Quellcode:
  if (myThread <> nil) then
  begin
    if not myThread.Suspended then
    begin
      myThread.Terminate;
      while not myThread.Finished do
        sleep(10);
    end
    else
    begin
      myThread.FreeOnTerminate := false; //  <-------- hinzugefügt
      myThread.Free;
    end;
  end;
Danke.

himitsu 27. Apr 2012 11:10

AW: Freigeben eines suspended Threads
 
Du solltest dich entscheiden, wer hier die Kontrolle hat.
- entweder du, dann FreeOnTerminate immer auf false und manuelles Free
- oder der Thread, dann FreeOnTerminate true und niemals Free

UliBru 27. Apr 2012 11:38

AW: Freigeben eines suspended Threads
 
Zitat:

Zitat von himitsu (Beitrag 1163818)
Du solltest dich entscheiden, wer hier die Kontrolle hat.
- entweder du, dann FreeOnTerminate immer auf false und manuelles Free
- oder der Thread, dann FreeOnTerminate true und niemals Free

Himitsu,

einfach danke. Mir fällt es wie Schuppen von den Haaren ...
Die meisten Beuspiele sind immer mit FreeOnTerminate := true; und so bin ich da ebenfalls reingestolpert.
Aber die DH sagt auch
Zitat:

If you want to communicate with the thread or otherwise interact with it, including telling it when to terminate, FreeOnTerminate should never be used. Calling Free on a TThread will set Terminated := True and then block until the thread terminates.
Und so löst sich alles einfach auf mit:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  myThread := TmyThread.Create(true);
  //... evtl. weitere Initialisierung, daher createsuspended
  myThread.Start;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Free;
end;
Das klappt egal ob der Thread gestartet ist oder nicht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:19 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