AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Freigabe Thread

Ein Thema von AJ_Oldendorf · begonnen am 12. Feb 2021 · letzter Beitrag vom 16. Feb 2021
Antwort Antwort
Seite 3 von 3     123   
AWeber

Registriert seit: 12. Feb 2013
19 Beiträge
 
#21

AW: Freigabe Thread

  Alt 12. Feb 2021, 18:37
Hallo,

Was ich in deinem Originalcode für kritisch halte ist die Sequenz aus .Terminate; gefolgt von .free; da der Aufruf von Terminate lediglich das Ende des Threads einleitet aber bei der Rückkehr der Thread ggf. noch läuft und du einen laufenden Thread frei gibst. Ich verwende steht's die Sequenz aus.

.Terminate;
.WaitFor;
.free;

Auch würde ich davon abraten den Thread direkt im .Execute freizugeben. Was du mit deinem OnReady Ereignis tust.

André
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.144 Beiträge
 
Delphi 10.3 Rio
 
#22

AW: Freigabe Thread

  Alt 12. Feb 2021, 18:37
Ich würde in so einem Fall auch TTask.Run nehmen...
es sei den,
Ich will nicht den Overhead und erzeuge mir vorab einen Thread. Diese kille ich am Ende des Programms.
Der Thread wartet auch einen TEvent und verbraucht keine Taktzyklen, starten aber in wenigen Pico Sekunden.
Dafür erzeuge ich ggf. eine Queue in die ich neue Werte schreibe und der Thread startet, wenn das passiert ist.
Oder halt nur einen Wert. Also Werte an Thread übergeben, SetEvent aufrufen fertig. Wenn der Thread die Arbeit erledigt hat,
legt er sich wieder schlafen...

Oder ich nutze FreeOnTerminate und gebe dem Thread ein Notifyer Interface mit, dass dann die Werte halten kann, wenn der Thread schon
lange tot ist.

Zum Beispiel so:
Delphi-Quellcode:
program Project13;

{$APPTYPE CONSOLE}

uses
  System.Classes
, System.SysUtils
, Windows
;

Type
  INotify = Interface
    ['{27E27AAC-63A6-4289-8B58-BCD4039AAE6C}']
    Procedure Ready(Value : Integer);
  End;

  TNotify = Class(TInterfacedObject,INotify)
    strict private
      Procedure Ready(aValue : Integer);
    private
      fValue : Integer;
      fOnReady : TProc<Integer>;
    public
      Constructor Create(aProc : TProc<Integer>);
      Destructor Destroy;override;
  end;

  TWorker = Class(TThread)
    Protected
      Procedure Execute;override;
    private
      fNotify : INotify;
    public
      Constructor Create(aNotify : INotify);
  End;


{ TNotify }

constructor TNotify.Create(aProc: TProc<Integer>);
begin
  Inherited Create;

  fOnReady := aProc;
end;

destructor TNotify.Destroy;
begin
  fOnReady(fValue);

  inherited;
end;

procedure TNotify.Ready(aValue: Integer);
begin
  fValue := aValue;
end;

{ TWorker }

constructor TWorker.Create(aNotify: INotify);
begin
  fNotify := aNotify;

  FreeOnTerminate := true;

  inherited Create(false);
end;

procedure TWorker.Execute;
begin
  Sleep(5000);
  fNotify.Ready(42);
end;

var
  Worker : TWorker;
begin
  try
    Worker := TWorker.Create(TNotify.Create(Procedure (aValue : Integer)
      begin // Still Thread Context
       Writeln(aValue,' MainThread:',Windows.GetCurrentThreadId() = System.MainThreadID);
      end));
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Natürlich kann ich daraus auch einen INotify<T> und TWorker<T> machen und das dann für alle möglichen Typen verwenden.
In diesem Fall, würde ich den Execute Teil, ggf. Überschreiben.

Mavarik
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
385 Beiträge
 
Delphi 12 Athens
 
#23

AW: Freigabe Thread

  Alt 15. Feb 2021, 15:01
TTask habe ich ehrlich gesagt noch nie genutzt. Müsste ich mir mal angucken.
Das Beispiel von Mavarik sieht mehr irgendwie zu "viel" aus. Da ist der einfache Thread mit seinem Create/Destroy und Execute für mich übersichtlicher, sicherlich aber Ansichtssache.
  Mit Zitat antworten Zitat
DieDolly

Registriert seit: 22. Jun 2018
2.175 Beiträge
 
#24

AW: Freigabe Thread

  Alt 15. Feb 2021, 15:07
Zitat:
Das Beispiel von Mavarik sieht mehr irgendwie zu "viel" aus.
Für den normalen Hausgebrauch definitiv viel zu viel. Da kann man quasi alles von wegschmeißen.

Bleib bei deinem Thread der jetzt funktioniert und gut.
Ansonsten sieht das mit dem TTask abgespeckt so aus. Dein Ready-Event packst du am Ende wie bei deinem Thread selber rein
Delphi-Quellcode:
 TTask.Run(
  procedure
  begin
   // Code
  end);
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.144 Beiträge
 
Delphi 10.3 Rio
 
#25

AW: Freigabe Thread

  Alt 16. Feb 2021, 17:45
Das Beispiel von Mavarik sieht mehr irgendwie zu "viel" aus. Da ist der einfache Thread mit seinem Create/Destroy und Execute für mich übersichtlicher, sicherlich aber Ansichtssache.
Naja mehr als ein Thread Create/Destroy ist das ja auch nicht - eigentlich noch viel zu einfach für den Hausgebrauch!

Zitat:
Das Beispiel von Mavarik sieht mehr irgendwie zu "viel" aus.
Für den normalen Hausgebrauch definitiv viel zu viel. Da kann man quasi alles von wegschmeißen.
Naja, eigentlich kann man davon NIX wegschmeißen. Das ist einfach ein super simple Methode um eine Benachrichtigung
zu erhalten, wenn der Thread fertig ist.

Normalerweise mache ich das noch aufwendiger!

Folgendes Beispiel:

In einem Form soll eine Aufgabe im Hintergrund ausgeführt werden...

Klar kann man das als "Schön-Wetter-Code" schreiben mit:

Delphi-Quellcode:
Procedure TForm1.Button1OnClick(Sender : TObject);
begin
  Button1.Enabled := false;
 
  TTask.Run(Procedure
    begin
      Sleep(5000); // of was richtiges.
      TThread.Queue(Nil,Procedure
        begin
          Edit1.Text := 'Thread ist fertig und hat: 42 ermittelt');
          Button1.Enabled := true;
        end);
    end);
end;
1. Was ist, wenn der Sleep eine Abfrage auf einen WebServer ist, der nicht wiederkommt oder ein Timeout hat von 5 Min.
2. Was ist, wenn das eine lange SQL-Abfrage ist die einfach ewig dauert?

Problem - der Button, geht nicht wieder auf Enabled... Toll..
Was aber wenn der User das Fester bereits wieder geschlossen hat?

Peng Exeption und die fängt auch erstmal keine ab... Man kann natürlich da noch ein try except drum setzen...

OK - Dann das Beispiel mit einem eigenen TThread...
Was ist wenn der Thread im Execute etwas aufruft, das nicht wieder kommt und damit steht?
Richtig, ein TThread.Destroy signalisiert Terminate aber das wir leider nicht ausgeführt.
Wenn also das Thread im FormOnDestroy oder wo auch immer freigegeben werden soll, bleibt das Fenster offen und die Anwendung steht.

Ich brauche also wenigstens ein Handle, das OutOfScope geht, wenn ich das Form schließe. Das OutOfScope darf nicht versuchen den Thread frei zu geben, sonst steht die Anwendung wieder.
Ich nehme das "nur" als signal, um den OnFinish-Class back mitzuteilen, dass er nicht mehr aufs Form zugreifen darf.

Und der Thread? - Naja, der lebt als tote Instance solange, bis die Routine im Execute mal zurück kommt oder das Programm beendet wird.
Das kann ich auch 10x versuchen... Die wenigen bytes stören mich nicht. Leider gibt es - außer mit einem OutOfProcess Server keine andere Möglichkeit den Thread zu zerstören.
Aber ein OutOfProcess Thread wäre dann hierfür vielleicht doch etwas "zu viel"...


Mavarik
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#26

AW: Freigabe Thread

  Alt 16. Feb 2021, 18:52
Zitat:
Was aber wenn der User das Fester bereits wieder geschlossen hat?
Einfach: Am Anfang im Queue nochmal prüfen, ob das Fenster noch da ist (z.B. über Screen.Forms das Self prüfen), bevor darauf zugegriffen wird.
Während des Queue kann das Fenster dann anschließend nicht mehr verschwinden. (außer man hat ein Application.ProgressMessage, einen Dialog oder Ähnliches darin)


Bei Dateioperationen auf eine Netzwerkfreigabe, da kann es auch schonmal ewig hängen.
Da kann man entweder Asynchron arbeiten, oder auch von außerhalb via MSDN-Library durchsuchenCancelIo abbrechen.

Auch viele Netwerkkomponenten und auch DB-Komponenten haben eine Funktion um von außerhalb Operationen in einem anderen Thread abzubrechen.


Falls es keinen Timeout gibt, oder der nicht immer funktioniert, kann man z.B. beim Schließen des Fensters dennoch einen Abbruch einleiten.
Den Thread selbst aber hart abzuschießen (MSDN-Library durchsuchenTerminateThread) ist aber niemals eine Lösung, denn wenn der z.B. grade dabei ist sich beim Speichermanager (FastMM) Seicher zu holen oder freizugeben und da grade in dem Moment eine CriticalSection gesperrt ist, kann man sich einen schönen Deadlock in anderen Threads einfangen.
$2B or not $2B

Geändert von himitsu (16. Feb 2021 um 18:57 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.144 Beiträge
 
Delphi 10.3 Rio
 
#27

AW: Freigabe Thread

  Alt 16. Feb 2021, 20:17
Einfach: Am Anfang im Queue nochmal prüfen, ob das Fenster noch da ist (z.B. über Screen.Forms das Self prüfen), bevor darauf zugegriffen wird.
Während des Queue kann das Fenster dann anschließend nicht mehr verschwinden. (außer man hat ein Application.ProgressMessage, einen Dialog oder Ähnliches darin)
Ja ok, man kann die Self Instance in der Forms-Liste (im queue) suche... Darüber habe ich in der Tat noch nicht nachgedacht... Nette Idee!
Weil ein Assigned(Self) geht logischerweise nicht.

Falls es keinen Timeout gibt, oder der nicht immer funktioniert, kann man z.B. beim Schließen des Fensters dennoch einen Abbruch einleiten.
Wenn der Code im Execute zu 100% unter meiner Kontrolle ist - ok, dann kann ich auf Terminated abtesten. Das ist einfach.

Den Thread selbst aber hart abzuschießen (MSDN-Library durchsuchenTerminateThread) ist aber niemals eine Lösung
Genau, deshalb meine Lösung. Wenn ich das wirklich braucht, ist der Overhead klein und für die harten Fälle dann doch einen neuen Prozess erzeugen, der
sein eigenes Memory Management hat und ggf. den Thread killt und den Speicher aufräumt.

Mavarik
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 3     123   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:09 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