Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi AThread.WaitFor gibt Fehler "Das Thread Handle ist ungültig" (https://www.delphipraxis.net/142183-athread-waitfor-gibt-fehler-das-thread-handle-ist-ungueltig.html)

BlueStarHH 23. Okt 2009 11:07


AThread.WaitFor gibt Fehler "Das Thread Handle ist ungü
 
Hallo,

ich habe einge eigene Thread-Klasse erstellt. Threads dieser Klasse sollen, wenn sie mit der Execute-Methode fertig sind, automatisch freigegeben werden. Deshalb ist AThread.FreeOnTerminate := True; gesetzt. Jedoch soll es auch die Möglochkeit geben, den Thread per Button-Click vor Ende der Execute-MEthode abzubrechen. Im Beispiel unten passiert das mit Button2Click. Dort tritt auch der Fehler auf: Wird Button2Click ausgelößt, wenn der Thread noch läuft ist alles ok. Wenn der Thread jedoch schon beendet ist, gibt es den Fehler "Das Thread Handle ist ungültig". Unz war bei AThread.WaitFor; An dieser STelle muss jedoch gewartet werden, weil danach noch Code folgt, der erst ausgeführt werden darf, wenn der Thread nicht mehr läuft.

Wie bekomme ich also beides (Beenden per Klick und automatisch freigeben) unter einem Hut?

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyThread = class(TThread)
  public
    procedure Execute; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    AThread: TMyThread;
    procedure MyThreadTerminate(Sender: TObject);
  public
    { Public-Deklarationen }
  end;



var
  Form1: TForm1;

implementation

{$R *.dfm}

//Erzeugt den Thread
procedure TForm1.Button1Click(Sender: TObject);
begin
  AThread := TMyThread.Create(True);
  AThread.Priority := tpNormal;
  AThread.FreeOnTerminate := True;
  AThread.OnTerminate := MyThreadTerminate;
  AThread.Resume;
end;

//Gibt dem Benutzer die Möglichkeit, den Thread zu Beenden
procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(AThread) then
  begin
    AThread.Terminate;
    AThread.WaitFor; //Hier fehler!
  end;

  //Hier steht noch Code, der erst ausgeführt werden darf, wenn AThread beendet ist.
end;

procedure TForm1.MyThreadTerminate(Sender: TObject);
begin
  AThread := nil;
end;


{ TMyThread }

procedure TMyThread.Execute;
var
  i: Integer;
begin
  i := 0;
  while not Terminated do
  begin
    sleep(100);
    inc(i);

    if i = 100 then //Beendet den Thread nach 10 Sekunden. Nur zum Testen.
     break;
  end;
end;

end.

Klaus01 23. Okt 2009 11:49

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
Hallo,


Delphi-Quellcode:
//Gibt dem Benutzer die Möglichkeit, den Thread zu Beenden
procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(AThread) then
  begin
    AThread.Terminate; // hier wird der Thread auf nil gesetzt, siehe Deine OnTerminate Routine
    AThread.WaitFor; //Hier fehler!
  end;

  //Hier steht noch Code, der erst ausgeführt werden darf, wenn AThread beendet ist.
end;
Noch eine Anmerkung, Du bekommst nicht mit wenn Dein Thread "normal" terminiert.

Grüße
Klaus

Grüße
Klaus

fajac 23. Okt 2009 12:19

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
Wenn FreeOnTerminate gesetzt ist, geht WaitFor schlicht nicht.
Folgendes Szenario:

Delphi-Quellcode:
  // Im MainThread:
  ThreadInstance.Terminate;
  // -> Threadwechsel
  // ThreadInstance terminiert und verschwindet aus dem Speicher
  // -> Threadwechsel zum MainThread
  ThreadInstance.WaitFor; // ThreadInstance hat noch einen Wert, ist aber ungültig -> Exception
Also: Wenn du unbedingt auf den Thread warten musst, dann geht das nur wenn du ihn hinterher selbst freigibst.

Uwe Raabe 23. Okt 2009 12:21

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
Zitat:

Zitat von BlueStarHH
Wie bekomme ich also beides (Beenden per Klick und automatisch freigeben) unter einem Hut?

Klaus hat ja schon erklärt, warum der Fehler auftaucht: du wartest auf einen Thread, der sich beim Beenden selbst frei gibt. Das kann leicht schief gehen.

Eine Möglichkeit ist, beim Button-Click ein Flag zu setzen und den Code, der nach Beenden des Threads ausgeführt werden soll, im MyThreadTerminate aufzurufen.

Delphi-Quellcode:
procedure TForm1.MyThreadTerminate(Sender: TObject);
begin
  AThread := nil;
  if FlagDoSomeCode then begin
    FlagDoSomeCode := false;
    DoSomeCode;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(AThread) then
  begin
    FlagDoSomeCode := true;
    AThread.Terminate;
  end
  else begin
    DoSomeCode;
  end;
end;

gsh 23. Okt 2009 12:55

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
So müsste es funktionieren:
Delphi-Quellcode:
//Erzeugt den Thread
procedure TForm1.Button1Click(Sender: TObject);
begin
  AThread := TMyThread.Create(True);
  AThread.Priority := tpNormal;
  //AThread.FreeOnTerminate := True; //Nicht automatisch freigeben
  //AThread.OnTerminate := MyThreadTerminate; //Braucht man nicht außer du willst noch was anderes darin machen
  AThread.Resume;
end;

//Gibt dem Benutzer die Möglichkeit, den Thread zu Beenden
procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(AThread) then
  begin
    AThread.Terminate;
    AThread.WaitFor;
    FreeAndNil(AThread);
  end;

  //Hier steht noch Code, der erst ausgeführt werden darf, wenn AThread beendet ist.
end;

Uwe Raabe 23. Okt 2009 13:39

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
Zitat:

Zitat von gsh
So müsste es funktionieren:
Delphi-Quellcode:
//Erzeugt den Thread
procedure TForm1.Button1Click(Sender: TObject);
begin
  AThread := TMyThread.Create(True);
  AThread.Priority := tpNormal;
  //AThread.FreeOnTerminate := True; //Nicht automatisch freigeben
  //AThread.OnTerminate := MyThreadTerminate; //Braucht man nicht außer du willst noch was anderes darin machen
  AThread.Resume;
end;

//Gibt dem Benutzer die Möglichkeit, den Thread zu Beenden
procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(AThread) then
  begin
    AThread.Terminate;
    AThread.WaitFor;
    FreeAndNil(AThread);
  end;

  //Hier steht noch Code, der erst ausgeführt werden darf, wenn AThread beendet ist.
end;

Mit dieser Lösung wird der Thread aber nicht freigegeben, wenn Button2 nicht geklickt wird!

gsh 23. Okt 2009 13:42

Re: AThread.WaitFor gibt Fehler "Das Thread Handle ist
 
Zitat:

Zitat von Uwe Raabe
Mit dieser Lösung wird der Thread aber nicht freigegeben, wenn Button2 nicht geklickt wird!

Dann muss man das gleiche einfach beim Programm beenden auch machen. :roll:


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz