Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TTask.run und Form.close wie geht das richtig? (https://www.delphipraxis.net/209109-ttask-run-und-form-close-wie-geht-das-richtig.html)

fisipjm 27. Okt 2021 14:04

Delphi-Version: 10.4 Sydney

TTask.run und Form.close wie geht das richtig?
 
Hi mal wieder in die Runde, in letzter Zeit spam ich das Forum ganz schön zu:|, aber die Hilfe ist einfach immer spitze :thumb:

Folgendes "Problem".

Ich habe eine Form als "Muster Form" die Ruft optisch immer in gleicher Optik aufbereitete aber unterschiedliche Daten ab.
Auf der Form liegen komponenten zum REST Abruf und eine TAniIndicator komponente. ich hab im Grunde aktuell 2 Events, show und close. Die hab ich folgendermaßen aufgebaut und die Funktionieren auch im normalen Programmablauf.


Delphi-Quellcode:
procedure TMainForm.FormShow(Sender: TObject);
begin
 StringGridBindSourceDB1.Visible:=false;
  AniIndicator1.Position.X:= width/2 - AniIndicator1.Width;
  AniIndicator1.Position.Y:= Height/2 - AniIndicator1.Height;
  AniIndicator1.Enabled:=true;
  TTask.run(
  procedure
  begin
    LaaaaaangsameRESTAbfrageMachen;
    tthread.Synchronize(nil,procedure
    begin
      StringGridBindSourceDB1.Visible := true;
      AniIndicator1.Enabled:=false;
      AniIndicator1.Visible:=false;
    end);
  end);
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := TCloseAction.caFree;
end;
Ich bin komplett neu im Thema parallele Programmierung und hab das Gefühl da gibt's noch sehr viel für mich zu lernen. Mein Problem ist, wenn der Benutzer ungeduldig ist und die Form schon während des Ladevorgangs Schließt, dann crasht mir die Form komplett. Ich bekomme erst mal eine AccessViolation und danach ist die Form aber weiterhin im Objektinspektor verfübar anstatt sauber freigegeben. Ich geh mal davon aus ich muss das irgendwie im Thread abfangen, aber ich habe absolut keinen Ansatz wie.
Vielen Dank schon mal :-)

himitsu 27. Okt 2021 14:55

AW: TTask.run und Form.close wie geht das richtig?
 
Delphi-Quellcode:
TThread.Synchronize(nil,procedure
begin
  if not (hier prüfen, ob die Form noch vorhanden ist) then
    Exit;
  StringGridBindSourceDB1.Visible := true;
Natürlich nicht auf Self oder irgendwas von der Form zugreifen.

Self kann man maximal verwenden, um z.B. in Screen.Forms zu suchen und dort ausschließlich den Zeiger vergleichen.
Gleichzeitig hoffen, dass es keine neue Form gibt, welche inzwischen an der alten Stelle ihren Speicherplatz fand.

Und nicht auf die Idee kommen vor dem Synchronize zu prüfen, weil während diesem Aufruf kann die Form immernoch verschwinden.




Aber, da du garantiert in LaaaaaangsameRESTAbfrageMachen auf Dinge in der Form zugreifst, bleibt nur noch OnCanClose der Form zu nutzen und wenn der Thread noch läuft, dann das Schließen abberechen.
Achtung: Free/Destroy im Code aufgerufen ignoriert OnClose und OnCloseQuery.

Und natürlich hast du da auch aufgepasst, dass im LaaaaaangsameRESTAbfrageMachen alles thread-save ist.

Uwe Raabe 27. Okt 2021 15:01

AW: TTask.run und Form.close wie geht das richtig?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Na, da hast du jetzt aber Glück :)

Ich plane gerade einen Artikel über genau diese Problematik. Dort wird ein Interface als Vermittler verwendet.

Das Beispielprojekt für den Artikel hänge ich hier einfach mal ohne weitere Erklärung an. Statt des REST-Aufrufs wird hier zwar eine Dateisuche als long running task verwendet, aber das Prinzip ist dasselbe. Bei Unklarheiten einfach fragen.

fisipjm 27. Okt 2021 15:48

AW: TTask.run und Form.close wie geht das richtig?
 
Zitat:

Zitat von himitsu (Beitrag 1496692)
Delphi-Quellcode:
TThread.Synchronize(nil,procedure
begin
  if not (hier prüfen, ob die Form noch vorhanden ist) then
    Exit;
  StringGridBindSourceDB1.Visible := true;
Natürlich nicht auf Self oder irgendwas von der Form zugreifen.

Self kann man maximal verwenden, um z.B. in Screen.Forms zu suchen und dort ausschließlich den Zeiger vergleichen.
Gleichzeitig hoffen, dass es keine neue Form gibt, welche inzwischen an der alten Stelle ihren Speicherplatz fand.

Und nicht auf die Idee kommen vor dem Synchronize zu prüfen, weil während diesem Aufruf kann die Form immernoch verschwinden.




Aber, da du garantiert in LaaaaaangsameRESTAbfrageMachen auf Dinge in der Form zugreifst, bleibt nur noch OnCanClose der Form zu nutzen und wenn der Thread noch läuft, dann das Schließen abberechen.
Achtung: Free/Destroy im Code aufgerufen ignoriert OnClose und OnCloseQuery.

Und natürlich hast du da auch aufgepasst, dass im LaaaaaangsameRESTAbfrageMachen alles thread-save ist.

Okay, jetzt bin ich maximal verwirrt :-D

Wenn ich nicht self verwenden kann (klingt logisch), was nutze ich dann?

LaaaaaangsameRESTAbfrageMachen holt sich über eine TBackendEndpoint komponente einen Stream und schiebt ihn eine FDMemtable. Was könnte da denn nicht Threadsafe sein?

Dein letzter Vorschlag hört sich nicht wirklich gut für mich an, das würde ja bedeuten der Bediener kann die Maske nicht schließen so lange der Thread noch läuft, sprich die Daten noch nicht geladen sind. Das würde ich gern vermeiden.

himitsu 27. Okt 2021 16:02

AW: TTask.run und Form.close wie geht das richtig?
 
Der Zeiger in Self kann genutzt werden, zum Suchen.
Vergleiche mit Screen.Forms prüft ja nur den Zeiger, aber nicht den Objektinhalt.

Wenn die Form schon weg ist, dann ist natürlich das Objekt, worauf "Self" zeigt, inkl. allem anderen dieser Form (abgesehn von lokalen Variablen und Funktionsparametern) auch weg.



Eine böse globale Variable oder ein Interface, um den "bin weg"-Status zu übergeben, das ginge ebenfalls.




Nja, an FDMemtable hängt doch bestimmt was dran?
z.B. ein Grid
Und schon macht es peng.

Hier könnte man aber
* entweder die Memtable vorübergehend von der DataSource abhängen
* oder die DataSource auf Enabled=False stellen
* oder schauen, ob das Grid eine Speerfunktion besitzt

Nur weil das Grid vielleicht unsichtbar ist, holt es sich dennoch intern schon die aktuellen Daten (reagiert auf Ereignisse der DataSource/DataSet)

fisipjm 28. Okt 2021 07:09

AW: TTask.run und Form.close wie geht das richtig?
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1496695)
Na, da hast du jetzt aber Glück :)

Ich plane gerade einen Artikel über genau diese Problematik. Dort wird ein Interface als Vermittler verwendet.

Das Beispielprojekt für den Artikel hänge ich hier einfach mal ohne weitere Erklärung an. Statt des REST-Aufrufs wird hier zwar eine Dateisuche als long running task verwendet, aber das Prinzip ist dasselbe. Bei Unklarheiten einfach fragen.

Moin Uwe,
schau mir dein Projekt gerade an, ich muss echt noch viel lernen:oops:.
Eine sache Off Topic, hast du eine gute Quelle oder Buchempfehlung um das Konzept und den Nutzen von Interfaces zu verstehen?

Ich glaube im groben habe ich es verstanden. Bei meinem Projekt ergibt sich aber jetzt ein Anschlussproblem. Aktuell ist mein Design so, das dass Laden beim show stattfindet die Main Form wird abgeleitet und lädt dann eben die "Grundfunktionen". Jetzt Gibt es aber den Fall, dass ich bei unterschieldichen Masken weitere Funktionalität (Felder, Werte , etc..) zur Verfügung stellen muss. Natürlich hat meine abgeleitete Form keinen Plan davon das in der PartenClass noch ein Thread läuft, dass führt dazu das ich in einen Deathlock laufe, wenn ich in der abgeleiteten Form an der GUI rumspielen will. Wäre das mit dem Interface auch gelöst? Ich befürchte nicht :-(

fisipjm 28. Okt 2021 07:12

AW: TTask.run und Form.close wie geht das richtig?
 
Zitat:

Zitat von himitsu (Beitrag 1496701)
Eine böse globale Variable oder ...

Moin,

hast du ein Beispiel für mich, nicht umbedingt um es zu benutzen, eher um es zu verstehen. Für mich sind Interfaces aktuell noch sehr abstrakt.

TigerLilly 28. Okt 2021 07:15

AW: TTask.run und Form.close wie geht das richtig?
 
Wenn du ein Fenster schließen möchtest, obwohl da noch ein Task läuft, musst du dieses tun:
1. das Schließen des Fensters abbrechen
2. den Task nach Möglichkeit rasch beenden

Du kannst in 1. dem User eine Info geben, dass da ein Task noch läuift + er es später nochmal probieren soll.
Du kannst in 1. einen Timer starten, der das Schließen nach xxx Sekunden automatisch nochmal probiert.

freimatz 28. Okt 2021 07:37

AW: TTask.run und Form.close wie geht das richtig?
 
Könnte man nicht
1. das Schließen des Fensters abbrechen
2. den Task informieren, dass er sich weiter Arbeit sparen kann
3. Das Fenster unsichtbar machen (der Anwender kann dann weiter machen)
4. Wenn der Task fertig ist das Fenster schließen

Uwe Raabe 28. Okt 2021 08:58

AW: TTask.run und Form.close wie geht das richtig?
 
Zitat:

Zitat von fisipjm (Beitrag 1496708)
schau mir dein Projekt gerade an, ich muss echt noch viel lernen:oops:.

Das kann aber wohl jeder hier sagen - mich eingeschlossen. Der Artikel dazu wird dann hoffentlich Erleuchtung bringen.

Zitat:

Zitat von fisipjm (Beitrag 1496708)
Eine sache Off Topic, hast du eine gute Quelle oder Buchempfehlung um das Konzept und den Nutzen von Interfaces zu verstehen?

Da fällt mir spontan Coding in Delphi von Nick Hodges ein.

Zitat:

Zitat von fisipjm (Beitrag 1496708)
Wäre das mit dem Interface auch gelöst? Ich befürchte nicht :-(

Die Beschreibung ist dazu noch nicht konkret genug. Lösen lässt sich in der Regel aber fast alles. Ob nun mit Interfaces oder was anderem muss man sehen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:44 Uhr.
Seite 1 von 2  1 2      

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