Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   TTask/ITask + Synchronze + OnDestroy (https://www.delphipraxis.net/206572-ttask-itask-synchronze-ondestroy.html)

TigerLilly 8. Jan 2021 07:01

AW: TTask/ITask + Synchronze + OnDestroy
 
Nein. Das Synchronize stellt ja eben sicher, dass der Button noch existiert. Wäre bei Thread.Queue anders.

Und ich möchte den Task ja canceln, da hilft wait nicht.

shebang 8. Jan 2021 08:13

AW: TTask/ITask + Synchronze + OnDestroy
 
Damit funktioniert es bei mir:
Delphi-Quellcode:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if Assigned(fTask) then begin
    fTask.Cancel;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := false;
  Button1.Text := 'Task running';
  fTask := TTask.Run(procedure()
    begin
      repeat
        if TTask.CurrentTask.Status = TTaskStatus.Canceled then
          Exit; // Exit statt Break
        Sleep(10);
        TThread.Synchronize(nil, procedure()
        begin
          Button1.Text := DateTimeToStr(Now);
        end);
      until false;
      Sleep(100);
      TThread.Synchronize(nil, procedure()
      begin
        Button1.Enabled := true;// Diese beiden Zugriffe müssen
        Button1.Text := 'Start Task'; // auch synchronisiert werden
      end);
    end);
end;

TiGü 8. Jan 2021 09:06

AW: TTask/ITask + Synchronze + OnDestroy
 
Ich habe mir das mal umformatiert mit TProc und TThreadProcedure Variablen, weil ich diese durchaus valide Schreibweise mit den geschachtelten anonymen Funktionen nicht so mag.
Nach dem FormDestroy ist das Formular und seine Komponenten schon weg. Daher die Prüfung mit Assigned(Button1), ob der Button überhaupt noch valide da ist.

Delphi-Quellcode:
unit Unit2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls,
  System.Threading;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    fTask: ITask;
    procedure DoCancelTask;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormDestroy(Sender: TObject);
begin
  DoCancelTask;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MainTaskProc: TProc;
begin
  Button1.Enabled := false;
  Button1.Text := 'Task running';

  MainTaskProc := procedure()
    var
      UpdateDateTime: TThreadProcedure;
      ReactivateButton: TThreadProcedure;
    begin
      UpdateDateTime := procedure()
        begin
          if Assigned(Button1) then
          begin
            Button1.Text := DateTimeToStr(Now);
          end;
        end;

      ReactivateButton := procedure()
        begin
          if Assigned(Button1) then
          begin
            Button1.Enabled := true;
            Button1.Text := 'Start Task';
          end;
        end;

      repeat
        if TTask.CurrentTask.Status = TTaskStatus.Canceled then
        begin
          Break;
        end;
        Sleep(10);
        TThread.Synchronize(nil, UpdateDateTime);
      until false;

      Sleep(100);

      TThread.Synchronize(nil, ReactivateButton);
    end;

  fTask := TTask.Run(MainTaskProc);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DoCancelTask;
end;

procedure TForm1.DoCancelTask;
begin
  if Assigned(fTask) then
  begin
    fTask.Cancel;
  end;
end;

end.

Uwe Raabe 8. Jan 2021 09:29

AW: TTask/ITask + Synchronze + OnDestroy
 
Zitat:

Zitat von TiGü (Beitrag 1480539)
Nach dem FormDestroy ist das Formular und seine Komponenten schon weg. Daher die Prüfung mit Assigned(Button1), ob der Button überhaupt noch valide da ist.

Wenn das Form und seine Komponenten schon weg sind (ich vermute, das heißt freigegeben), dann kann Assigned(Button1) immer noch True liefern, obwohl der Zugriff darauf dann auf undefiniertem Speicher erfolgt. Das kann dann gut gehen - muss aber nicht.

TigerLilly 8. Jan 2021 09:44

AW: TTask/ITask + Synchronze + OnDestroy
 
Zitat:

Zitat von shebang (Beitrag 1480537)
Damit funktioniert es bei mir:
Delphi-Quellcode:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if Assigned(fTask) then begin
    fTask.Cancel;
  end;
end;

Nein, das funktioniert nur, wenn der Task schnell genug beendet. Wenn das länger dauert, wird das Formular geschlossen und der TAsk läuft noch - weil er mit Beenden noch nicht fertig ist.

Daher die Anforderung, zu warten, bis der Thread SICHER beendet ist.

shebang 8. Jan 2021 10:33

AW: TTask/ITask + Synchronze + OnDestroy
 
Dann wäre die Frage, ob ein Task für deine aktuelle Aufgabe geeignet ist. Wenn ich mir die verfügbaren Methoden von TTask so anschaue, dann sieht es für mich eher so aus, dass Tasks für kurze kleine Aufgaben gedacht sind, auf deren Erfüllung man wartet. Dein Beispiel enthält ja eine Schleife, die abgebrochen werden muss, es gibt kein reguläres Ende. Ich würde an dieser Stelle wohl eher einen Thread nehmen.

TiGü 8. Jan 2021 10:40

AW: TTask/ITask + Synchronze + OnDestroy
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1480541)
Zitat:

Zitat von TiGü (Beitrag 1480539)
Nach dem FormDestroy ist das Formular und seine Komponenten schon weg. Daher die Prüfung mit Assigned(Button1), ob der Button überhaupt noch valide da ist.

Wenn das Form und seine Komponenten schon weg sind (ich vermute, das heißt freigegeben), dann kann Assigned(Button1) immer noch True liefern, obwohl der Zugriff darauf dann auf undefiniertem Speicher erfolgt. Das kann dann gut gehen - muss aber nicht.

Vollkommen richtig.
Zumindest hat das jetzt dreimal anhand dieses Minimalbeispiels funktioniert.
Meine Hand würde ich dafür aber nicht ins Feuer legen.

Zumindest ist das besser als das Rumgehampel mit
Delphi-Quellcode:
while Button1.Enabled = false do begin
     Application.ProcessMessages;
end;
Da weiß ich gar nicht, wo ich da ansetzen soll.

Je nach echter Anforderung würde ich ggf. den Schreib-Overhead mit einem echten TThread-Abkömmling vorschlagen, da man dann die volle Kontrolle hat und gescheit mit einem TEvent warten kann.

Übrigens wundere ich mich, dass noch keiner gemeckert hat, weil im Ursprungspost einfach mal hart im externen Threadkontext auf Eigenschaften der GUI-Komponenten zugegriffen wird (Button.Enabled/Text).
Das steht zwar alles visuell in der TForm1.Button1Click, läuft aber sozusagen im Execute eines externen Threads.
Da wurden andere sonst immer virtuell an den Ohren gezogen. :twisted:

Uwe Raabe 8. Jan 2021 12:01

AW: TTask/ITask + Synchronze + OnDestroy
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich weiß ja nicht, ob das für den realen Anwendungsfall passt, aber in solchen Fällen verwende ich dann ein Zwischenobjekt. Ich hab da mal was vorbereitet...

TigerLilly 8. Jan 2021 12:03

AW: TTask/ITask + Synchronze + OnDestroy
 
Zitat:

Zitat von shebang (Beitrag 1480557)
Dann wäre die Frage, ob ein Task für deine aktuelle Aufgabe geeignet ist. Wenn ich mir die verfügbaren Methoden von TTask so anschaue, dann sieht es für mich eher so aus, dass Tasks für kurze kleine Aufgaben gedacht sind, auf deren Erfüllung man wartet. Dein Beispiel enthält ja eine Schleife, die abgebrochen werden muss, es gibt kein reguläres Ende. Ich würde an dieser Stelle wohl eher einen Thread nehmen.

Das erschließt sich mir nicht. TTask kapselt doch nur den Zugriff auf Threads. Die Endlos-Schleife samt Abbruch ist nur zu Testzwecken, ändert an der Aufgabenstellung nichts. In echt beendet der Task natürlich, wenn man ihn lässt.

Warum sollte hier ein Thread tauglicher sein als ein Task?

TigerLilly 8. Jan 2021 12:07

AW: TTask/ITask + Synchronze + OnDestroy
 
Zitat:

Zitat von TiGü (Beitrag 1480559)
Je nach echter Anforderung würde ich ggf. den Schreib-Overhead mit einem echten TThread-Abkömmling vorschlagen, da man dann die volle Kontrolle hat und gescheit mit einem TEvent warten kann.

Nochmal. Ich möchte das Fenster schliueßen + allfällige Tasks dabei beenden. Nur dann(!!) habe ich ein Problem. Das "warten" ist ja leicht gesagt - aber wie ist die Frage. Zeig mir was besseres als mein Rumgehample.


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

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz