Timer Funktion während FindAllFiles

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Timer Funktion während FindAllFiles

Beitrag von Socke »

mse hat geschrieben:
ruewa hat geschrieben:Der Timer (jedenfalls der LCL-TTimer) läuft in einem eigenen Thread und triggert von dort aus irgendwann das Timer-Event.

Da wäre ich mir nicht so sicher da es vom widgetset abhängt.

Die LCL-Time werden vom Widgetset oder Betriebssystem bereitgestellt und dann in die Message-Queue der Anwendung eingereiht. Threads werden nicht verwendet.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Timer Funktion während FindAllFiles

Beitrag von mschnell »

ruewa hat geschrieben: Der Timer (jedenfalls der LCL-TTimer) läuft in einem eigenen Thread und triggert von dort aus irgendwann das Timer-Event.

Das ist ein Irrtum. Der Timer der LCL verwendet Widget-Set Funktionialitäten (z.B. Windows, oder GTK) um das Event direkt im Mainthread zu schmeißen.

Edit: Socke war schneller :D

-Michael

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Timer Funktion während FindAllFiles

Beitrag von ruewa »

Stimmt, Ihr habt recht. Ich habe das für GTK gerade nochmal nachgeschlagen: https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html#g-timeout-source-new. Danke für die Korrektur.

Es ist der TFPTimer, der eigene Threads verwendet:
Unit fptimer, Zeile 169:
Default implementation. Threaded timer, one thread per timer.


Ach, das Gedächtnis...

Okay, das ändert aber nichts daran, daß fziebell gut beraten wäre, den Timer rauszuschmeißen und den 260.000-fachen Aufruf von Application.ProcessMessages zu reduzieren. Eine simple Zählvariable innerhalb der Schleife kostet am wenigsten Ressourcen und ob der Bildschirm alle 0,2 Sekunden oder alle 0,6 Sekunden aktualisiert wird, spielt in dem Fall keine Rolle - es geht ja nur darum, daß das Programm keine dreiviertel Minute lang einfriert.

Gruß Rüdiger

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Timer Funktion während FindAllFiles

Beitrag von soerensen3 »

Dabei sollte man aber berücksichtigen, dass man auch nicht die Suche abbrechen kann oder das Programm auf normalen Weg beenden kann (zumindest nicht flüssig). Aber das ist vielleicht auch in deinem Fall akzeptabel (Kommt auf den Einzelfall an).

ApplicationQueueAsyncCall oder Queue sind wahrscheinlich die bessere Variante, aber auch schwerer zu verwenden, da kein Beispiel dazu da ist (oder war da nicht eins im examples ordner?). Die Seite zu Multithreads müsste da wahrscheinlich auch mal angepasst werden.

Ich würde wahrscheinlich versuchen es mit Threads umzusetzen, aber will dir da auch nichts aufzwingen. Zumal man sich mit Threads auch eine Menge Ärger einhandeln kann, da sie gerade beim debugging sehr problematisch sind.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Timer Funktion während FindAllFiles

Beitrag von mschnell »

soerensen3 hat geschrieben:Dabei sollte man aber berücksichtigen, dass man auch nicht die Suche abbrechen kann

-> TThread.Terminate

soerensen3 hat geschrieben:ApplicationQueueAsyncCall oder Queue sind wahrscheinlich die bessere Variante, aber auch schwerer zu verwenden.

Funktioniert ansonsten genau wie Synchronize, nur dass bei QueueAsynCall noch eine Zahl mit übergeben werden kann

-Michael

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Timer Funktion während FindAllFiles

Beitrag von soerensen3 »

mschnell hat geschrieben: soerensen3 hat geschrieben:Dabei sollte man aber berücksichtigen, dass man auch nicht die Suche abbrechen kann
-> TThread.Terminate

Ich meinte bei dem TImer, wenn Application.ProcessMessages nur einmal pro Sekunde aufgerufen wird.
Das ist eben der Vorteil bei Threads. Allerdings funktioniert TThread.Terminate nur, wenn im Execute Teil regelmäßig geprüft wird ob TThread.Terminated True ist.

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Timer Funktion während FindAllFiles

Beitrag von ruewa »

soerensen3 hat geschrieben:Dabei sollte man aber berücksichtigen, dass man auch nicht die Suche abbrechen kann oder das Programm auf normalen Weg beenden kann (zumindest nicht flüssig).

Das habe ich gerade mal probiert, an einem alten Projekt, das mithilfe von ImageMagick alle jpgs im Verzeichnis analysiert und ab einer bestimmten Grenzgröße verkleinert. Die Form enthält u.a. einen Run-Button und einen Close-Button. Die Bearbeitungsschleife ist innerhalb der OnClick-Prozedur des Run-Buttons.

Dazu habe ich der Form eine Boolsche Variable namens "Running" spendiert, diese bei OnCreate auf false initialisiert und folgenden Code in die RunBtnClick-Prozedur eingefügt:

Code: Alles auswählen

procedure TForm1.RunBtnClick(Sender: TObject)
var
  cnt : integer;
  {...}
begin
  Running := not Running;
  if Running then RunBtn.Caption := '&Stop'
  else begin
    RunBtn.Caption := '&Ok';
    exit;
  end;
  Application.ProcessMessages;
  {...}
  Cnt := -1;
  try
    for i := 0 to FileList.Count - 1 do
      begin
        if not Running then break;
        inc(cnt);
        if cnt = 100 then
        begin
          Application.ProcessMessages;
          cnt := 0;
        end;
        {...}
  finally
    {...}
    Running := false;
    RunBtn.Caption := '&Ok';
  end;
 


(Haltet Euch bitte nicht mit Detailkritik auf, das geht bestimmt eleganter, ich hab das wirklich nur ganz auf die Schnelle hingerotzt...)

Das funktioniert völlig problemlos, die Ausführung stoppt nach einem Stop-Click zuverlässig, sobald infolge der cnt=100-Bedingung ein ProcessMessages aufgerufen wird. Was interessanterweise während der Abarbeitung der Schleife nicht funktioniert, ist der Close-BitBtn (der einfach via Kind auf bkClose gestellt ist). Ich vermute, der fragt noch irgendein CanClose-Flag ab, das habe ich jetzt nicht weiter untersucht.

Gruß Rüdiger

Edit: Aufräumaktion im Finally-Block hinzugefügt, so kann's verwendet werden ("Running: Boolean;" muß dann noch in die Formdeklaration eingesetzt werden).
Zuletzt geändert von ruewa am Di 25. Nov 2014, 13:00, insgesamt 3-mal geändert.

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Timer Funktion während FindAllFiles

Beitrag von soerensen3 »

Ok aber Cnt ist ja nicht 3000 in dem Fall sondern 100, dann reagiert er schneller. Da kann man ja versuchen einen sinnvollen Wert zu finden.
Das mit dem Close liegt vermutlich daran, dass Running ja nicht auf False gesetzt wird. Durch ein OnClose Ereignis könnte man das vermutlich lösen.

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Timer Funktion während FindAllFiles

Beitrag von ruewa »

soerensen3 hat geschrieben:Ok aber Cnt ist ja nicht 3000 in dem Fall sondern 100, dann reagiert er schneller.


Nein, in meinem Fall viel langsamer, weil dabei 100 Dateien eingelesen werden. Ist aber auch egal, die 3000 bezogen sich auf die Zahlen von fziebell, bei ihm würde das eine halbe Sekunde dauern. Die Zahl ist völlig beliebig.

Das "Running" hat mit dem Close-Event nichts zu tun, das ist meine eigene Variable, die wird nur in runBtnClick ausgewertet. Ehrlich gesagt, ich hab mir nicht mal die Mühe gemacht, das am Ende der Prozedur aufzuräumen, mich hat nur interessiert, ob es prinzipiell funktioniert. Das flieg jetzt auch wieder raus...

Gruß Rüdiger

soerensen3
Beiträge: 104
Registriert: Fr 22. Jun 2012, 01:51
OS, Lazarus, FPC: Fedora-Linux 23 (Korora) Lazarus 1.6 FPC 3.0
CPU-Target: 64Bit
Wohnort: Bonn

Re: Timer Funktion während FindAllFiles

Beitrag von soerensen3 »

ruewa hat geschrieben:Das "Running" hat mit dem Close-Event nichts zu tun, ...


Nicht ganz, entscheidend ist folgende Zeile:

Code: Alles auswählen

if not Running then break;

Sonst verzögert die Ausführung das Beenden vom Programm.

ruewa
Beiträge: 153
Registriert: Sa 12. Apr 2014, 14:43

Re: Timer Funktion während FindAllFiles

Beitrag von ruewa »

soerensen3 hat geschrieben:
ruewa hat geschrieben:Das "Running" hat mit dem Close-Event nichts zu tun, ...


Nicht ganz, entscheidend ist folgende Zeile:

Code: Alles auswählen

if not Running then break;

Sonst verzögert die Ausführung das Beenden vom Programm.


Langsam! Die Ausführung wird gestartet, und danach spielt sich alles innerhalb der RunBtnClick-Methode ab. Dort wird Running auf true gesetzt und der Button auf "Stop" umbenannt. Danach geht's in die For..do-Schleife, wo die eigentliche Bearbeitung stattfindet. Klicke ich jetzt ein zweites Mal auf den (jetzt Stop-) Button, wird die RunBtn-Click-Methode ein zweites Mal aufgerufen. Das passiert aber erst, nachdem innerhalb der Schleife cnt=100 erreicht und das ProcessMessages aufgerufen wird. Dann wird der zweite Durchlauf der RunBtnClick-Methode dazwischengeschoben, stellt dort aber im Wesentlichen nur Running wieder auf false und bricht dann via exit ab. Dann geht es zurück in die Schleife, die beim nächsten Durchlauf abgebrochen wird, weil inzwischen das Running-Flag wieder auf false steht.

Was soll ich sagen? So funktioniert es, das war mir nicht von vorneherein klar. Der Zweitaufruf von RunBtnClick wird genauso in die Queue gestellt wie die Aktivierung des Close-Buttons. Schiebt man nun ein ProcessMessages dazwischen, wird der Zweitaufruf von RunBtnClick zwischendurch ausgeführt, der Close-Befehl aber nicht (der wird erst ausgeführt, wenn die Schleife regulär beendet ist). Der Close-Mechanismus weiß überhaupt nichts von der Existenz der "Running"-Variable. Warum, weshalb - keine Ahnung...

Aber vielleicht reden wir auch aneinander vorbei. Klar ist: Mein obiger Code führt nicht zu einem instantanen Abbruch, die Schleife läuft solange weiter, bis das Programm via ProcessMessages aktualisiert wird. Das Intervall dafür kann man aber frei wählen, und halt auch ohne Timer, Threads und dergleichen.

Gruß Rüdiger

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Timer Funktion während FindAllFiles

Beitrag von mschnell »

soerensen3 hat geschrieben:Ich meinte bei dem TImer, wenn Application.ProcessMessages nur einmal pro Sekunde aufgerufen wird.

Eine Sekunde Delay ist doch wohl flott genug zum Abbrechen, oder ?
soerensen3 hat geschrieben:Das ist eben der Vorteil bei Threads. Allerdings funktioniert TThread.Terminate nur, wenn im Execute Teil regelmäßig geprüft wird ob TThread.Terminated True ist.

Das muss man immer !

Code: Alles auswählen

...
procedure ...Execute;
...
while not Terminated do begin
  ...
end;
...


-Michael

Antworten