Einzelnen Beitrag anzeigen

Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.473 Beiträge
 
Delphi 12 Athens
 
#18

AW: Threadklasse mit Event aktualisiert nicht

  Alt 29. Aug 2024, 09:10
Offensichtlich ist dein Ziel, Aufgaben im Hintergrund abzuwickeln, wärend die Oberfläche weiterhin bedienbar bleibt.
Der Gedanke ist die eigentliche Aufgabe durch einem zusätzlichen Thread auszuführen.
Der braucht aber zum Ausführen der Aufgabe ebenfalls einige Zeit.
Deshalb kann das Ergebnis nicht direkt nach dem Resume abgerufen werden.

Es gibt zwei Möglichkeiten:

1. Warten bis der Thread beendet ist und danach den Hauptthread fortsetzen, um das Ergebnis auszugeben.
Das ist offensichtlich nicht sehr sinnvoll, da dann der Hauptthread in der Zwischenzeit nicht reagiert und die Oberfläche nicht bedienbar ist.
(Man kann das umgehen, aber das ist auch nicht sinnvoll.)

2. Man übergibt dem Thread eine Methode, die automatisch beim Beenden ausgeführt wird.
Der Hauptthread läuft in der Zwischenzeit weiter und kann sich um die Oberfläche kümmern.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Test: TSeriesThread;
begin
  Button1.Enabled := False;

  Test := TSeriesThread.Create(false);
  Test.OnTerminate := DoOnTerminate;
  Test.FreeOnTerminate := True;
  Test.Resume;
end;

procedure TForm1.DoOnTerminate(Sender: TObject);
begin
  ListBox1.Items.AddStrings((Sender as TSeriesThread).Episodes);

  Button1.Enabled := True;
end;
Synchronize wird nur benötigt, wenn der Thread eine Methode aufruft, die auf die VCL zugreift (z.B. Form1.ListBox1 ).
Damit kann man diese Aufgabe an den Hauptthread übergeben. Der Thread wartet dann bis der Hauptthread Zeit hat diese auszuführen.
Im OnTerminate ist der Thread aber bereits beendet. Dieses Ereignis führt der Hauptthread aus und benötigt kein extra Synchronize.
Solche Methoden muss man natürlich so kurz wie möglich halten und möglichst selten aufrufen.
Andernfalls ist der Hauptthread wieder blockiert, was wir gerade vermeiden wollen.

Deshalb gehört alles was in TForm1.MyTest steht, direkt in TSeriesThread.Execute (oder TSeriesThread private Methoden die dort aufgerufen werden).
Falls es mehrere verschiedene Abläufe gibt, die schon beim Start des Thread feststehen, leite für jeden eine Klasse mit eignem Execute ab und führe die konkrete Klasse aus.
Den internen Ablauf über einen Parameter zu steuern ist auch ok.
Deine Variante mit einer Methode, die im Thread ausgeführt, aber außerhalb deklariert ist, birgt immer das Risiko das ohne Synchronize auf die VCL zugegriffen wird.
Delphi-Quellcode:
procedure TSeriesThread.Execute;
begin
  Title := 'Test';
  Episodes.Add('Test Episode1');
  Episodes.Add('Test Episode2');
end;
Zum Schluss sollte man auch verhindern, dass das Formular beendet wird, bevor der TSeriesThread beendet ist:
Delphi-Quellcode:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := Button1.Enabled;
end;

Geändert von Blup (29. Aug 2024 um 09:20 Uhr)
  Mit Zitat antworten Zitat