Threadfehler: Der Handle ist ungültig (6), wenn er versucht, einen unterbrochenen Thread zu löschen

8

In einem gegebenen Beispiel erhalte ich eine Ausnahme beim Aufruf von AThread.Free.

%Vor%

Ich habe zwei Fragen:

  1. Wie soll ich AThread instance von TThread in einem gegebenen Beispiel freigeben?

  2. Ich verstehe nicht, warum TThread.Destroy vor dem Destroying Resume aufruft. Was ist der Sinn dieses?

Wodzu 10.01.2012, 14:59
quelle

2 Antworten

15

Sie können FreeOnTerminate nicht auf True und auf Free in der Thread-Instanz festlegen. Du musst das eine oder das andere machen, aber nicht beides. Wie es aussieht, zerstört dein Code den Thread zweimal. Sie dürfen ein Objekt niemals zweimal zerstören und natürlich, wenn der Destruktor zum zweiten Mal ausgeführt wird, treten Fehler auf.

Was passiert, ist, dass nichts passiert, seit Sie den Thread suspendiert haben, bis Sie den Thread explizit freigeben. Wenn Sie das tun, setzt der Destruktor den Thread fort und wartet darauf, dass er abgeschlossen wird. Dies führt dazu, dass Free erneut aufgerufen wird, weil Sie FreeOnTerminate auf True setzen. Dieser zweite Aufruf von Free schließt das Handle. Dann kehren Sie zum Thread-Prozess zurück und rufen % co_de auf % Dies schlägt fehl, weil das Handle des Threads geschlossen wurde.

Wie Martin in dem Kommentar erwähnt, dürfen Sie ExitThread nicht direkt erstellen, da die Methode TThread abstrakt ist. Außerdem sollten Sie TThread.Execute nicht verwenden, was veraltet ist. Verwenden Sie Resume , um mit der Ausführung eines unterbrochenen Threads zu beginnen.

Persönlich möchte ich nicht Start verwenden. Wenn diese Funktion verwendet wird, wird der Thread in einem anderen Thread zerstört, aus dem er erstellt wurde. Sie verwenden es normalerweise, wenn Sie die Instanzreferenz vergessen möchten. Das lässt Sie dann unsicher, ob der Thread zerstört wurde, wenn Ihr Prozess beendet wird, oder ob er sich selbst beendet oder während der Prozessbeendigung freigibt.

Wenn Sie FreeOnTerminate verwenden müssen, müssen Sie sicherstellen, dass Sie FreeOnTerminate nicht aufrufen, nachdem Sie Free auf FreeOnTerminate gesetzt haben. Die naheliegende Lösung besteht also darin, True unmittelbar nach dem Aufruf von FreeOnTerminate auf True zu setzen und dann die Thread-Instanz zu vergessen. Wenn Sie Ausnahmen haben, bevor Sie zum Start bereit sind, können Sie den Thread sicher freigeben, da Sie Start an diesem Punkt immer noch FreeOnTerminate haben.

%Vor%

Ein eleganterer Ansatz wäre, die gesamte Initialisierung in den Konstruktor False zu verschieben. Dann würde der Code wie folgt aussehen:

%Vor%     
David Heffernan 10.01.2012, 15:44
quelle
5

Die Situation ist in Ihrem Fall sehr kompliziert.

Erstens, Sie befreien einen suspendierten Thread nicht wirklich. Ein Thread wird in destructor fortgesetzt:

%Vor%

Da Terminate vor Resume aufgerufen wird, wird die Methode Execute niemals ausgeführt, und der Thread wird sofort beendet, nachdem er fortgesetzt wurde:

%Vor%

Sieh dir nun die letzte Zeile an - du rufst destructor ( Thread.Free ) vom Destruktor selbst auf! Fantastischer Fehler!

Um Ihre Fragen zu beantworten:

  1. Sie können FreeOnTerminate:= True in Ihrem Code nicht verwenden;
  2. Sie sollten Embarcadero fragen, warum TThread so konzipiert ist; meine Vermutung - ein bisschen Code ( DoTerminate method) sollte im Thread-Kontext while ausgeführt werden Thread wird beendet.

Sie können eine Feature-Anfrage an QC senden: Fügen Sie FFreeOnTerminate:= False zu TThread.Destroy implementation:

hinzu %Vor%

Das sollte einen rekursiven Destruktor-Aufruf verhindern und Ihren Code gültig machen.

    
kludg 10.01.2012 16:31
quelle