Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Prüfen ob Thread noch läuft (https://www.delphipraxis.net/85003-pruefen-ob-thread-noch-laeuft.html)

Schwedenbitter 24. Jan 2007 14:44


Prüfen ob Thread noch läuft
 
Hallo,

ich möchte mittels meines Programms Dateien verschieben. Da es viele Dateien sein können und ich das ganze über einen langsamen VPN-Tunnel machen muss, würde das Programm ewig still stehen. Aus diesem Grunde habe ich die Prozeduren für das Kopieren und Löschen der Dateien in einen Thread gepackt. So weit - so gut. Allerdings habe ich immer noch folgende Probleme:

Da das Verschieben im Thread stattfindet, könnte es passieren, dass der Benutzer das Fenster schließt und das Programm damit beendet. Dann bestünde aber die Gefahr, dass offene Dateien zurückblieben, was auf die Dauer gesehen sehr unschön wäre. Die Eigenschaft Terminated gibt mir leider nur zurück, ob der Thread beendet werden soll. Aber nicht ob und wann er es nach dem Abarbeiten seiner Aufgaben selbst macht. Andere brauchbare Eigenschaften konnte ich in der Hilfe nicht finden. Ich habe mir bisher über eine globale Variable geholfen. Diese wird vor Ausführung des Thread auf True gesetzt und im Thread nach dem letzten Befehl erst auf False.

Gibt es bessere Methoden und falls ja, welche?

Außerdem bekomme ich beim Beenden des Programms hin und wieder die Fehlermeldung Exception der Klasse EOSError aufgetreten / Systemfehler. Code: 1400 Ungültiges Fensterhandle.

Was hat das zu bedeuten?

Schließlich habe ich trotz Verwendung eines Thread immer noch nicht in den Griff bekommen, dass sich das Fenster flüssiger bewegen lässt. Mir ist klar, dass BlockRead und BlockWrite bewusst größere Datenmengen verarbeiten und bei einem schlechten Durchsatz Verzögerungen hervorrufen. Aber ich dachte, dass das bei Ausführung im Thread im Hintergrund liefe und man in Ruhe weiterarbeiten kann.

Was mache ich falsch?

Falls Bedarf besteht, kann ich auch Quellcode reinsezten. Ich bitte dann aber um Erklärung was gebraucht wird; 400 Zeilen sind zuviel.

[edit=SirThornberry]Titel korrigiert - Mfg, SirThornberry[/edit]

sirius 24. Jan 2007 15:05

Re: Prüfen ob Thread noch läuft
 
z.B. kann man das mit Klassenmethoden machen. Da kannst du jederzeit abfragen, ob noch ein Thread läuft, auch wenn das Objekt selber nicht mehr existiert:
Delphi-Quellcode:
type
  tmythread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    procedure Execute; override;
  public
    class function isrunning:boolean;
  end;

implementation

var running:integer=0;
{}

procedure tmythread.Execute;
begin
  inc(running);
  { Thread-Code hier einfügen }
  dec(running);
end;

class function tmythread.isrunning:boolean;
begin
  result:=running>0;
end;
inc und dec kann man auch in den constructor/destructor schreiben.


Dein Fehler kennn ich nicht. Aber ich würde vermuten, dass der Thread noch nicht beendet ist, wenn du den Hauptthread schließt. Fragst du in execute regelmäßig die Variable terminated ab?

stahli 24. Jan 2007 15:14

Re: Prüfen ob Thread noch läuft
 
Hallo Schwedenbitter,

Auszug aus dem Delphi-Thread-Demo:
Delphi-Quellcode:
procedure TThreadSortForm.StartBtnClick(Sender: TObject);
begin
  RandomizeArrays;
  ThreadsRunning := 3;
  with TBubbleSort.Create(BubbleSortBox, BubbleSortArray) do
    OnTerminate := ThreadDone;
  with TSelectionSort.Create(SelectionSortBox, SelectionSortArray) do
    OnTerminate := ThreadDone;
  with TQuickSort.Create(QuickSortBox, QuickSortArray) do
    OnTerminate := ThreadDone;
  StartBtn.Enabled := False;
end;

procedure TThreadSortForm.ThreadDone(Sender: TObject);
begin
  Dec(ThreadsRunning);
  if ThreadsRunning = 0 then
  begin
    StartBtn.Enabled := True;
    ArraysRandom := False;
  end;
end;
Stahli

shmia 24. Jan 2007 16:25

Re: Prüfen ob Thread noch läuft
 
Wenn ein Thread seine Aufgaben nicht ordnungsgemäss oder vollständig erfüllen konnte,
sollte man im Thread das Property ReturnValue auf einen Fehlercode setzen.
Am besten speichert man alle Threads, die man erzeugt hat, in einer Liste (TObjectList).
Im Event OnTerminate sorgt man dann dafür, dass der Thread aus der Liste entfernt wird.

Durch das Speichern aller Threads in der Liste hat man die volle Kontrolle und kann auch jederzeit die Anzahl der laufenden Threads ermitteln.

Pfoto 24. Jan 2007 16:51

Re: Prüfen ob Thread noch läuft
 
Hi!

Wenn das Abarbeiten der Aufgabe im Thread das Hauptfenster immer noch teilweise zum Stehen bringt
oder etwas ruckelt, dann deutet das noch auf eine nicht korrekte Lösung hin.
Ist jetzt schwer etwas von hier zu vermuten...


Aber noch zum Beenden:

Probier das hier im OnCloseQuery Ereignis des Forms:
Delphi-Quellcode:
with myThread do
begin
  Terminate;
  WaitFor;
  Free;
end;
FreeOnTerminate muss aber dann anfangs False sein.


Gruß
Pfoto

Schwedenbitter 24. Jan 2007 20:58

Re: Prüfen ob Thread noch läuft
 
Herzlichen Dank für die schnellen Antworten. Ich habe es jetzt mit dem Quellcode von sirius gemacht. Das funktioniert prima. Auf eine Liste verzichte ich, weil es nur einen Thread gibt. Werde mir das aber merken, falls ich mal was schwierigeres programmieren muss.

@Pfoto Ich will nicht behaupten, dass mein Code fehlerfrei ist. Schließlich bin ich absoluter Gelegenheitsprogrammierer und nehme Delphi nur, um mir die Arbeit auf Arbeit etwas einfacher zu machen. Allerdings habe ich Quelle und Ziel auf dieselbe Festplatte gelegt und eine 150 MB Datei für Versuchszwecke genommen. Fenster ruckelt kein bisschen. Liegt also wirklich am VPN. Was will man auch von 250 KBit/s upload bei DSL erwarten.
Den Quellcode habe ich probiert. Bei mir dauert es damit ca. 4 Sekunden, bis das Programm beendet ist, nachdem ich auf das Kreuz geklickt habe.

Ich habe jetzt auch die Quelle für die Exception gefunden. Allerdings weiß ich nicht, woran es wirklich liegt.
Ich hatte nach entsprechendem Quelltext aus dem Forum versucht, eine ProgressBar in eine Statusbar zu integrieren. Ich hatte zuerst die ProgressBar völlig gelöscht. Und siehe da, der Fehler trat nicht mehr auf. Anschließend ließ ich die ProgressBar drin. Allerdings separat und nicht mehr integiert. Der Fehler trat wieder auf. Jetzt ist sie ganz raus. Aber der Benutzer sieht jetzt leider nicht mehr, wie weit das Programm fortgeschritten ist. Schade.

alzaimar 24. Jan 2007 21:13

Re: Prüfen ob Thread noch läuft
 
Was ist denn bei dem Code von sirius, wenn man mehrere Threads startet? Dann klappt das nämlich nicht. Die Idee ist zwar ganz ok, aber eben nicht vollständig richtig.

sirius 25. Jan 2007 07:26

Re: Prüfen ob Thread noch läuft
 
Zitat:

Zitat von alzaimar
Was ist denn bei dem Code von sirius, wenn man mehrere Threads startet? Dann klappt das nämlich nicht. Die Idee ist zwar ganz ok, aber eben nicht vollständig richtig.

Jep, richtig, war ja auch nur so ein Ansatz.
Ich kann ja nicht immer Ansätze liefern, die komplett auf alle Probleme passen :zwinker:

Schwedenbitter 25. Jan 2007 07:32

Re: Prüfen ob Thread noch läuft
 
Zitat:

Zitat von alzaimar
Was ist denn bei dem Code von sirius, wenn man mehrere Threads startet?

Eigentlich sollte es auch mit mehreren Threads funktionieren. Wird einer gestartet, dann erhöht sich der Zähler um 1. Wird einer beendet, dann reduziert er sich wieder um 1. Macht im Ergebnis Null, wenn alle beendet sind. Dabei spielt es keine Rolle, in welcher zeitlichen Abfolge die Threads ablaufen.
Man muss meiner Meinung nach nur dafür sorgen, dass man bei den Terminated-Abfragen vor dem Beenden mitten im Thread auch eins runter zählt. Dann sollte es doch stimmen, oder?
Delphi-Quellcode:
procedure tmythread.Execute;
begin
  inc(running);
  { Thread-Code hier einfügen }
  if terminated then
  begin
    dec(running);
    exit;
  end;
  { Thread-Code-Ende }
  dec(running);
end;
Denn die Funktion IsRunning prüft nur, ob der Zähler Null ist.

sirius 25. Jan 2007 07:38

Re: Prüfen ob Thread noch läuft
 
Zitat:

Zitat von Schwedenbitter
Zitat:

Zitat von alzaimar
Was ist denn bei dem Code von sirius, wenn man mehrere Threads startet?

Eigentlich sollte es auch mit mehreren Threads funktionieren. Wird einer gestartet, dann erhöht sich der Zähler um 1. Wird einer beendet, dann reduziert er sich wieder um 1. Macht im Ergebnis Null, wenn alle beendet sind. Dabei spielt es keine Rolle, in welcher zeitlichen Abfolge die Threads ablaufen.
Man muss meiner Meinung nach nur dafür sorgen, dass man bei den Terminated-Abfragen vor dem Beenden mitten im Thread auch eins runter zählt. Dann sollte es doch stimmen, oder?

Denn die Funktion IsRunning prüft nur, ob der Zähler Null ist.

Ja das ist auch wieder richtig. Ich meinte ja: Je nach Anwendungsfall.
Ein Problem kriegt man z.B. mit dieser Variante, wenn deine Threads mit "freeonterminate=TRUE" laufen. Dann werden sie automatisch aus dem Speicher entfernt:
Wenn z.b ThreadInstanz1 bereits fertig ist und ThreadsInstanz2 noch läuft dann gibt dir "isRunning" True zurück und wenn du dann ThreadInstanz1.waitfor aufrufst, kriegts du eine Zugriffsverletzung.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:25 Uhr.
Seite 1 von 3  1 23      

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