Einzelnen Beitrag anzeigen

SvB

Registriert seit: 21. Okt 2004
Ort: Eckenroth
426 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#1

Thread .Terminate beim Beenden - Runtime Error 216

  Alt 11. Aug 2009, 23:41
Ich habe in einem D2007 Programm sinngemäß folgenden Code:

Delphi-Quellcode:
TmyThread = class(TThread)
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
  end;

constructor TmyThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
end;

destructor TmyThread.Destroy;
begin
  inherited;
end;

procedure TmyThread.Execute;
begin
  while not Terminated do begin
    // mach irgend etwas, berechne
    self.Suspend;
  end;
end;

.
.
.

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  myThread := TmyThread.Create(True);
  myThread.FreeOnTerminate := True;
  myThread.Resume; // Starte Thread und laufe einmal durch
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Terminate;
  if myThread.Suspended then begin
    myThread.Resume;
  end;
  // Was kann man hier einbauen um zu prüfen, ob der Thread beendet und zerstört ist
end;
Also der Thread läuft beim Starten einmal durch und legt sich dann selbst schlafen. Unter verschiedenen Umständen in meinem Programm wird der Thread ab und zu mal wieder aufgeweckt. Das funktioniert auch alles wunderbar und ohne Probleme.
Mein Problem ist allerdings, dass ab und zu beim Beenden vom Programm ein Runtime Error 216 kommt. Ich habe dann herausgefunden dass es am Thread liegt, bzw. dass er wohl noch nicht beendet und zerstört ist, das Hauptformular aber dann schon. Wenn ich das Programm über die IDE starte, dann kommt der Fehler fast gar nicht, wenn ich die EXE außerhalb der IDE starte, dann kommt der Fehler ziemlich oft.
Ich habe auch schon folgendes probiert:
Delphi-Quellcode:
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Terminate;
  if myThread.Suspended then begin
    myThread.Resume;
  end;
  myThread.WaitFor; // <----- neu
end;
aber dann gibts ein Fehler bei WaitFor, dass die Thread ID nicht stimmt (oder so ähnlich).

Wenn ich folgendes mache:
Delphi-Quellcode:
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Terminate;
  if myThread.Suspended then begin
    myThread.Resume;
  end;
  sleep(50); // kurze Pause
end;
dann gibt es nie einen Fehler, das gefällt mir aber nicht, einfach eine Pause da rein zu hauen.

Folgendes bringt mich auch nicht weiter:
Delphi-Quellcode:
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  myThread.Terminate;
  if myThread.Suspended then begin
    myThread.Resume;
  end;
  while myThread <> nil do begin // <----- neu
    sleep(50);
    Application.ProcessMessages;
  end;
end;
Das Problem dabei ist, dass myThread nach dem beenden und zerstören immer noch <> nil ist. Ich habe auch geprüft, dass beim Aufruf von Resume das Execute des thread verlassen wird und Destroy des Thread wird auch durchlaufen.

Habt Ihr eine Idee, was ich tun kann, wenn FreeOnTerminate := True und ich den Thread dann selbst terminiere, ich aber noch prüfen will, ob er wirklich beendet ist.

Danke
Sven
  Mit Zitat antworten Zitat