Frage an destructor, delphi, tthread – Eine geeignete Methode, um ein TThread-Objekt zu zerstören

15

Diese Frage mag trivial erscheinen, aber ich hoffe, Sie werden sie nicht ignorieren.
Bevor ein TThread-Objekt zerstört wird, muss normalerweise gewartet werden, bis der Thread, der die Methode TThread.Execute () aufgerufen hat, beendet ist. Nur dann können wir sicher sein, dass beispielsweise nicht mehr auf die Objekte zugegriffen wird, die im Destruktor der Klasse zerstört wurden. Daher ist es erforderlich, Terminate aufzurufen, um das Flag Terminated zu setzen, das der Thread überprüfen muss, um zu wissen, ob er beendet werden soll, und anschließend die WaitFor () - Methode aufzurufen.

Da der Thread möglicherweise angehalten wird, empfiehlt es sich, ihn vor dem Aufruf von WaitFor fortzusetzen, da sonst der aufrufende Thread blockiert wäre. Und weil der Thread mehrmals unterbrochen werden kann, sollte er gleich oft fortgesetzt werden, oder?

while Suspended do
  Resume;

Wenn der Thread suspendiert erstellt wurde, müssen wir nicht befürchten, dass die TThread.Execute () -Methode aufgerufen wird, wenn wir den Thread nur fortsetzen, um ihn zu beenden - dies wird nicht der Fall sein (bitte korrigieren Sie mich, wenn ich falsch liege).

Was ich angegeben habe, schlägt vor, die folgenden Codezeilen für jedes freizugebende TThread-Objekt zu verwenden:

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;

Wenn wir unsere Anwendung zerstören, die mehrere Threads erstellt hat, macht das Schreiben eines solchen Codeteils für jedes zu zerstörende TThread-Objekt den Code leider sehr lang und möglicherweise sogar undurchsichtig.

Daher bin ich zu dem Schluss gekommen, dass all dies in einem überschriebenen Destruktor der TThread-Klasse abgelegt werden kann, dank dessen es ausreichen würde, MyThread.Free (oder MyThread.Terminate, wenn MyThread.FreeOnTerminate gesetzt ist) aufzurufen, ohne sich darum zu kümmern, ob der Destruktor zerstört wurde Objekt ist ein TThread-Objekt oder nicht:

destructor TMyThread.Destroy;
begin
  //if FreeOnTerminate, the calling thread cannot wait for itself
  if GetCurrentThreadId <> ThreadId then
  begin
    Terminate;
    while Suspended do
      Resume;
    WaitFor;
  end;

  {free all objects created in this class}

  inherited Destroy;
end;

Verzeihen Sie, dass ich eine so grundlegende Frage stelle. Ich möchte jedoch Ihre Meinung dazu kennenlernen, wie - ich hoffe auf universelle Weise - TThread-Objekte zerstört werden können. Ich stelle diese Fragen, weil ich von den Codes meiner Arbeitskollegen erfahren habe, dass sie normalerweise das erste Codebeispiel zum Zerstören solcher Objekte verwendeten, aber sie prüften nie, ob die Threads, auf die gewartet wurde, nicht angehalten wurden, was ich als etwas gefährlich betrachtete, wenn die Threads könnte irgendwo im Code suspendiert sein. Deshalb habe ich versucht, einen universellen Weg zu finden, um die Objekte dieser Klasse zu zerstören, der den Code klarer und sicherer macht. Ich hoffe, ich habe es nicht schlimmer gemacht - was denkst du?

Vielen Dank für Ihre Anregungen im Voraus.

Eine Erinnerung an die Worte von Hamlets Lord Polonius: Kürze ist die Seele des Witzes Argalatyr

Deine Antwort

2   die antwort
8

einen Thread anzuhalten, so wie es keine universelle Möglichkeit gibt, einen Prozess (ordnungsgemäß) anzuhalten. Jeder ist anders.

Für einige Threads ist es ausreichend, den Wert für "its" festzulegenTerminated Eigentum über dieTerminate Methode. Andere Threads hingegen rufen Funktionen wieGetMessage oderMsgWaitForMultipleObjects, die blockiert, bis etwas passiert, z. B. eine Nachricht eingeht oder ein Kernel-Handle signalisiert wird.TThread.Terminate Beides kann nicht passieren, sodass diese Threads nicht aufhören zu laufen. Wenn ich solche Threads geschrieben habe, habe ich meine eigenen Funktionen bereitgestellt, um sie zu benachrichtigen, dass sie nicht mehr ausgeführt werden. Ich könnte anrufenPostThreadMessage um eine Nachricht in die Warteschlange des Threads zu zwingen, oder ich kann das Ereignis signalisieren, das die Thread-Klasse bereitgestellt hat, um sie über eine Anforderung zum Beenden zu benachrichtigen.

Machen Sie sich keine Sorgen, wenn Sie einen unterbrochenen Thread wiederaufnehmen möchten. Du solltest sie sowieso nicht aussetzen. Die einzige sichere Möglichkeit, einen Thread anzuhalten, besteht darin, dass sich der Thread selbst anhält. Sobald Sie dies getan haben, können Sie sicher sein, dass mindestens zwei Threads steuern, wann der Thread ausgeführt wird: der Thread selbst, um ihn anzuhalten, und mindestens einer andere Thread, um es wieder aufzunehmen. Ein Thread sollte die Kontrolle über seine eigene Ausführung haben.

Es wäre toll, wennTThread.Terminate waren virtuell. Dann könnte jede Thread-Klasse eine benutzerdefinierte Methode bereitstellen, um sich selbst zu benachrichtigen, dass sie nicht mehr ausgeführt werden soll. Einige konnten gerade einstellenTerminatedund andere können sich selbst Nachrichten senden, Ereignisse signalisieren oder tun, was sie sonst noch brauchen. Die nicht-virtuelle Methode funktioniert jedoch nicht gut mit Threads, die viel Zeit damit verbringen, auf andere Dinge zu warten. Der aktuelle Weg funktioniert nur für Threads, die häufig könnenUmfrage ihrTerminated Eigenschaften.

Einige Threads haben ihreFreeOnTerminate Eigenschaften festgelegt. Für diese Threads ist Ihr Code nicht sicher. Technisch ist es nicht sicher anzurufenirgendein Methoden für solche Objekte, da der Thread jederzeit beendet werden kann. Aber selbst wenn Sie wissen, dass der Thread noch ausgeführt wird und das Thread-Objekt noch vorhanden ist, wird das Objekt nach dem Aufruf von definitiv nicht mehr vorhanden seinTerminate. Sie können nicht anrufenWaitFor auf ein free-on-terminate Thread-Objekt, und Sie können definitiv nicht aufrufenFree.

8

was Sie vorschlagen, wird bereits im TThread.Destroy-Destruktor ausgeführt, und das Aufrufen von TMyThread.free wird genau das tun, was Sie vorschlagen. Um Objekte zu bereinigen, die der Thread-Klasse gehören, können Sie dies im OnTerminate-Ereignis ausführen, das als Teil der Logik zum Herunterfahren des Threads aufgerufen wird.

@Mariusz: Versuchen Sie, ohne Suspend () und Resume () zu codieren, und Sie werden dieses Problem nicht haben. Diese Methoden können sehr problematisch sein, wie Sie selbst festgestellt haben, und es gibt immer eine Möglichkeit, ohne sie zu programmieren. Lassen Sie den Thread stattdessen auf einem oder mehreren vom System bereitgestellten Synchronisationsprimitiven blockieren. Oder verwenden Sie Nachrichtenschleifen. Es gibt mehrere Antworten mit Informationen zum Multithreading hier auf SO in [delphi]. mghie
Ja, das stimmt, aber ich habe überprüft, dass der Thread nur dann wieder aufgenommen wird, wenn er angehalten wird, wenn der Destruktor aufgerufen wird. Wenn ich es während seiner Arbeit aussetze, führt das Aufrufen des Destruktors, ohne es wieder aufzunehmen, zu einem Deadlock. Aus diesem Grund suchte ich nach einer universellen Methode, um TThread-Objekte zu zerstören, die für jede Klasse, die von TThread erbt, in Ordnung wäre. Mariusz Schimke

Verwandte Fragen