Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Problem mit Task.Cancel (https://www.delphipraxis.net/209313-problem-mit-task-cancel.html)

stahli 21. Nov 2021 00:48

Problem mit Task.Cancel
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,

ich habe ein Problem, einen Task in einer komplexen Umgebung sicher abzubrechen.

In einem Testprojekt kann ich das Problem nicht nachstellen. Das reale Projekt (IDE-Experte) ist natürlich deutlich komplexer.

In dem Task wird zunächst synchronisiert über die VCL ein Wert ermittelt, dann verarbeitet und wieder synchronisiert in die VCL ausgegeben.
Im realen Projekt läuft die Datenverarbeitung in einem Interface-Objekt, dem der Task dazu für den evtl. Abbruch mit übergeben wird.

Wenn ich dort ein Sleep(50+) mit einbaue funktioniert der Abbruch auch.
Ohne Sleep wird die Exception von CheckCanceled nicht ausgelöst. Irgendwie scheint dann keine Zeit dafür zu sein.
Aber ein andauerndes Sleep ist natürlich bei sehr häufigen Schleifendurchläufen auch nicht praktikabel.

In dem Testprojekt habe ich die Berechnung jetzt noch nicht in ein eigenes Interface-Objekt ausgelagert.
Ansonsten ist das Grundprinzip etwa nachgestellt.

Das Testprojekt funktioniert allerdings mit und ohne Sleeps.

Warum mein reales Projekt nicht so funktioniert konnte ich noch nicht klären.
Wenn der Task nicht abgebrochen wird, dann mogelt sich der neue Task dazwischen, stellt die neuen Daten dar und dann werden die alten Daten weiter dargestellt.
Kann jemand das Problem anhand dieser etwas unscharfen Beschreibung nachvollziehen?


Delphi-Quellcode:
  procedure TForm1.ShowData;
  const
    MaxY = 100;
    MaxX = 5;
  var
    S: String;
  begin
    if Assigned(TestTask) and (TestTask.Status = TTaskStatus.Running) then
      begin
        OutputDebugString(PWideChar('-> ' + 'cancel'));
        TestTask.Cancel;
        OutputDebugString(PWideChar('<- ' + 'cancel'));
      end;

    TestTask := TTask.Create(
      procedure
      var
        Y, X: Integer;
        A  : Array[1..MaxY] of Array[1..MaxX] of String;
      begin
        try
          TThread.Synchronize(nil,
            procedure
            begin
              OutputDebugString(PWideChar('-> ' + 'snc GetData'));
              S := Edit1.Text;
              OutputDebugString(PWideChar('<- ' + 'snc GetData'));
            end);

          OutputDebugString(PWideChar('-> ' + 'calc')); // CALCULATION
          for Y := 1 to MaxY do
            begin
              for X := 1 to MaxX do
                begin
                  A[Y, X] := S;
                  TTask.CurrentTask.CheckCanceled();
                  OutputDebugString(PWideChar('...calc... ' + IntToStr(Y) + ', ' +
                    IntToStr(X) + ' "' + S + '"'));
//                Sleep(100);
                end;
            end;
          OutputDebugString(PWideChar('<- ' + 'calc'));

          TThread.Synchronize(nil,
            procedure
            var
              Y, X: Integer;
              S  : String;
            begin
              OutputDebugString(PWideChar('-> ' + 'snc ShowData'));
              Memo1.Clear;
              for Y := 1 to MaxY do
                begin
                  for X := 1 to MaxX do
                    begin
                      S := A[Y, X];
                      OutputDebugString(PWideChar('...show... ' + IntToStr(Y) + ', ' +
                        IntToStr(X) + ' "' + S + '"'));
                      Memo1.Text := Memo1.Text + S + ' ';
//                    Sleep(100);
                    end;
                  Memo1.Text := Memo1.Text + sLineBreak;
                end;
              OutputDebugString(PWideChar('<- ' + 'snc ShowData'));
            end);
        except
          on EOperationCancelled do
            Exit;
        end;
      end);
    TestTask.Start;
  end;

venice2 21. Nov 2021 03:56

AW: Problem mit Task.Cancel
 
Vielleicht eine dumme Antwort. (Wenn ja vergiß es einfach)
Unter umständen erstellst du irgendwo einen Deadlock schon mal mit TThread.Queue versucht an der stelle wo dein Problem auftritt?

Zitat:

Queue bewirkt, dass der in AMethod festgelegte Aufruf im Haupt-Thread asynchron ausgeführt wird, und verhindert somit Multithread-Konflikte.
Ich hatte zumindest ein ähnliches Problem in meiner TAudioVolume Componente.

stahli 21. Nov 2021 09:13

AW: Problem mit Task.Cancel
 
Ein Deadlock kann m.E. aktuell nicht vorliegen, da das Programm sich nicht aufhängt.
Lediglich der abzubrechende Task wird verspätet weiter bearbeitet.

Eine Queue wird mir wohl auch nicht helfen, da sich diese vermutlich noch schlechter unterbrechen lässt.

Danke aber dennoch.

stahli 21. Nov 2021 16:09

AW: Problem mit Task.Cancel
 
Ich habe einen offenbar funktionierenden und akzeptablen Workarround gefunden.

Aus dem Thread rufe ich MyProjekt.DoAllUnits auf und dort für jede Unit.DoAllLines...
Nach jeder Unit führe ich jetzt ein Sleep(100) aus. Die Verzögerung hält sich somit in Grenzen und die hinfälligen Tasks wurden bisher immer bei mir abgebrochen.

Als Workarround ist das erst mal ok. Wenn jemand noch einen besseren Tipp hat oder einen grundsätzlichen Fehler erkennt, wäre ich natürlich für eine Info dankbar.

Andreas13 22. Nov 2021 15:05

AW: Problem mit Task.Cancel
 
Hallo Stahli,
Du könntest evtl. die auf Delphi-Treff https://www.delphi-treff.de/tipps-tr...ndung-beenden/ beschrieben Routine
Delphi-Quellcode:
KillTask
ausprobieren. Vielleicht hilft es Dir.
Gruß, Andreas

stahli 24. Nov 2021 10:24

AW: Problem mit Task.Cancel
 
Danke für den Tipp. Ich merke mir das mal vor, aber meine aktuelle Lösung scheint mir übersichtlicher zu sein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:44 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