AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Bilder komprimieren und speichern mit Threads

Ein Thema von Schwedenbitter · begonnen am 28. Feb 2011 · letzter Beitrag vom 7. Mär 2011
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#11

AW: Bilder komprimieren und speichern mit Threads

  Alt 1. Mär 2011, 13:18
zumindest Append müsstest Du mit einer CS kapseln ...
ansonsten habe ich so ein komisches Bauchgefühl ...
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#12

AW: Bilder komprimieren und speichern mit Threads

  Alt 2. Mär 2011, 00:20
Zu früh gefreut:

Ich habe meinen Code jetzt mal unter realistischeren Bedingungen getestet. Dazu habe ich jeweils zwischen Append(); ein Sleep(); gepackt. Hintergrund ist der, dass der Scanner die Bilder auch nicht sofort auf einmal liefert.
Zudem habe ich den Thread zur besseren Lesbarkeit in eine eigene Unit gepackt.

Dabei ist mir ein weiterer Fehler aufgefallen.
Der Thread wird offenbar noch korrekt gestartet. Auch wenn das Ereignis an das MainForm erst später kommt, so sehe ich zeitnah nach dem Erstellen des Thread die 1. Datei auf dem Laufwerk erscheinen. Dann passiert aber lange nichts. Der Rest wird erst in die Dateien gespeichert, wenn alle Dateien geliefert wurden. Das ist aber leider nicht der Sinn vom Ganzen. Nach meinem Verständnis sollte der Thread, solange nicht Ende:=True; gesetzt ist, alles sofort wegspeichern, was in der Liste ist...

Ich habe die Änderungen vom Code wieder als zip-Datei angefügt und würde mich freuen, wenn mal jemand von den Profis drüber schauen und mir sagen könnte, wo mein Fehler liegt.

Gruß & Dank, Alex
Angehängte Dateien
Dateityp: zip SaveThread_2.zip (3,8 KB, 10x aufgerufen)
Alex Winzer
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#13

AW: Bilder komprimieren und speichern mit Threads

  Alt 2. Mär 2011, 07:48
Ich habe nicht alles nachvollzogen, aber ein paar Sachen sind mir aufgefallen:
1.) keine CS bei Append und Ende
2.) in diesem Block
Delphi-Quellcode:
FThread.Append(Bild);
Sleep(250);// -> 4 Bilder / 1 Sek.
läuft der Thread ja bereits.....
3.) wenn das:
Delphi-Quellcode:
Procedure TMainForm.RepeaterTimer(Sender: TObject);
Begin
   Repeater.Enabled:=False;
   ScannenClick(nil);
End;
ausgeführt wird, wird jedes mal eine neuer Thread losgetreten

Vielleicht schaut Sir Rufo mal drüber ....
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#14

AW: Bilder komprimieren und speichern mit Threads

  Alt 2. Mär 2011, 09:38
Erstmal danke fürs Drüberschauen!

1.) keine CS bei Append und Ende
Das kommt noch. Ich hatte es bereits drin, wollte aber wirklich jede mögliche Fehlerquelle für das beschriebene Phänomen ausschließen.

2.) in diesem Block
Delphi-Quellcode:
FThread.Append(Bild);
Sleep(250);// -> 4 Bilder / 1 Sek.
läuft der Thread ja bereits.....
Eben!
Auf meinem Rechner braucht er allein für das Umwandeln in png ca. 1 Sek/Bild. Er sollte an diese Stelle daher bereits genug zu tun haben, um noch während des Anfügens (Append(); )weiterer Bilder die bereits vorhandenen umzuwandeln.
Das macht er aber nicht, was ich wiederum nicht verstehe.

3.) wenn das:
Delphi-Quellcode:
Procedure TMainForm.RepeaterTimer(Sender: TObject);
Begin
   Repeater.Enabled:=False;
   ScannenClick(nil);
End;
ausgeführt wird, wird jedes mal eine neuer Thread losgetreten
Das ist ausdrücklich so gewollt!
Ich hatte ebenfalls bereits meine Code fürs Vergrößern/Verkleiner und/oder Drehen mit drin. Da erhielt ich hin und wieder - aber leider nicht wirklich reproduzierbar - eine EOutOfResources . Ich habe das Code-Fragment daher mal eine Weile ohne Benutzereingaben laufen lassen.
Man kann den Kreislauf ja jederzeit unterbrechen, indem man einfach den Haken rausnimmt. Dann hört der "Spuk" nach dem nächsten Thread-Ende auf!

Vielleicht schaut Sir Rufo mal drüber ....
Das wäre wirklich nett.

Gruß, Alex
Alex Winzer
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#15

AW: Bilder komprimieren und speichern mit Threads

  Alt 2. Mär 2011, 18:11
Ich bin wieder ein Stück weiter!

Die von mir zur Steuerung des Scanners verwendete Komponente TDelphiTwain liefert die Bilder immer per Ereignis an das Hauptprogramm. Ich habe dieses Verhalten nun nachgebaut, indem ich die Bilder nicht wie bisher mittels Schleife an den Thread übergebe, sondern per TTimer.OnTimer; . Dieses hängt nun - einem sehr schnellen Scanner gleich - aller 250 ms ein weiteres Bild an die Liste im Thread und das klappt jetzt:
Die Meldung "Alle Bilder geliefert..." kommt regelmäßig so ca. nachdem 17 Seiten bereits gespeichert wurden So war der Plan!

Dennoch finde ich das ein eigenartiges Verhalten. Scheinbar wird der Thread tatsächlich erst gestartet, nachdem die Procedure, in dem er erzeugt wurde, vollständig beendet ist. Das hätte ich nicht vermutet.
Kann jemand diese Beobachtung zumindest für TurboDelphi bestätigen?

Nachdem ich das nun - scheinbar endgültig - geklärt habe. Werde ich mich nun wieder den Problemen Stretchen und Drehen zuwenden.
Das hatte ich bereits getan, bevor ich merkte, dass das Speichern tatsächlich nicht so läuft, wie es soll. Ich hatte dabei mehrfach eine Exception EOutOfResources gefangen und würde hierzu ggf. gern mal nachfragen.

@Moderator
Soll ich dazu dann ein neues Thema aufmachen oder hier weiterschreiben?
Ich habe die aktuelle Version mal für die Nachwelt angefügt. Die vorhergehenden Code-Beispiele können bei Platzmangel ggf. gelöscht werden. Danke.

Gruß & Dank, Alex
Angehängte Dateien
Dateityp: zip SaveThread_p3.zip (3,8 KB, 10x aufgerufen)
Alex Winzer
  Mit Zitat antworten Zitat
Blup

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

AW: Bilder komprimieren und speichern mit Threads

  Alt 3. Mär 2011, 08:30
Der Zugriff auf FBilder muss durch eine Critical Section abgesichert werden.

Delphi-Quellcode:
self.Priority:=tpIdle
;
Natürlich macht der Thread so nur was, wenn der Hauptthread gerade nichts zu tun hat.
Beim Erzeugen des Formulars ist der Hauptthread aber schon beschäftigt.
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#17

AW: Bilder komprimieren und speichern mit Threads

  Alt 4. Mär 2011, 09:51
Der Zugriff auf FBilder muss durch eine Critical Section abgesichert werden.
Na gut, na gut. Das habe ich nun gemacht.

self.Priority:=tpIdle; Natürlich macht der Thread so nur was, wenn der Hauptthread gerade nichts zu tun hat.
Beim Erzeugen des Formulars ist der Hauptthread aber schon beschäftigt.
Das verstehe ich nicht ganz. Vom Grundsatz her ist mir das klar. Aber der Thread wird doch erst erzeugt und gestartet, wenn man auf den Button "Scannen" klickt. Da ist doch das Formular bereits erzeugt worden, oder wo ist mein Denkfehler.

Es läuft jetzt übrigens auf einem Testrechner seit mehr als 2 Stunden problemlos. Sorgen bereitet mir nur, dass FastMM mir 3 - wenn auch mit 620 Bytes sehr kleine - Speicherlecks bringt. Ich habe das Programm bereits mit Debug-DCU, map-Dateien etc. pp. compiliert. Allerdings kommen immer Meldungen mit TButton, TDialog usw. Die werden zwar vom Hauptprogramm verwendet. Ich dachte aber, dass sich der Compiler bei entsprechenden Komponenten selbst um die Freigabe kümmert...
Ich würde - falls noch jemand Muße hat - den aktuellen Code nochmal hochladen.

Am Schluss noch eine allgemeine, vielleicht auch marginale Frage:
Im Moment schicke ich vom Thread Ereignisse an den HauptThread und zwar so:
Delphi-Quellcode:
Procedure TSaveThread.MessageNext;
Begin
  If Assigned(FOnNext) Then
    FOnNext(self, FNext);
End;

Procedure TSaveThread.Execute;
Begin
  While (Not Terminated) Do
  Begin
    ... // <- tu irgendwas

    Syncronize(MessageNext);
  End;
End;
Kann man das bedenkenlos auch so machen:
Delphi-Quellcode:
Procedure TSaveThread.MessageNext;
Begin
  FOnNext(self, FNext);
End;

Procedure TSaveThread.Execute;
Begin
  While (Not Terminated) Do
  Begin
    ... // <- tu irgendwas

    If Assigned(FOnNext) Then
      Syncronize(MessageNext);
  End;
End;
Dann würde er nämlich nicht erst Syncronize aufrufen und in die andere Procedure springen müssen, wenn er vorher prüft, ob das Ereignis überhaupt zugewiesen ist.
Die 1. Variante habe ich mehrfach gesehen und gehe deshalb davon aus, dass sie richtig ist. Spricht etwas gegen die 2. Variante?

Gruß, Alex
Alex Winzer
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#18

AW: Bilder komprimieren und speichern mit Threads

  Alt 4. Mär 2011, 11:01
Wenn Du den Setter von FOnNext mit einer CS verriegelt hast spricht IMHO nichts dagagen, sonst könnte bei (wirst Du nicht machen) gleichzeitigen Zugriff Müll in FOnNext stehen.
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#19

AW: Bilder komprimieren und speichern mit Threads

  Alt 4. Mär 2011, 23:45
Wenn es nicht notwendig ist, dass diese "Message" synchron zum (bzw. im) Thread läuft, kannst du auch tatsächliche Windows Messages an dein Fensterhandle schicken, und dort mit einem Eventhandler reagieren. (MSDN-Library durchsuchenSendMessage()) Das würde das ganze noch eine Spur mehr entkoppeln, ist aber daran gebunden, dass im Handler weder Thread auf MainForm noch MainForm auf Thread Felder zugreifen. So angelegte Konzepte "behagen" mir in der Regel mehr, als harte synchrone Callbacks, zumal man mit zu vielen letzterer den Nutzen von Threads auch gerne mal schmälern bis vernichten kann.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Blup

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

AW: Bilder komprimieren und speichern mit Threads

  Alt 7. Mär 2011, 09:43
Im Prinzip ist diese Lösung zulässig:
Delphi-Quellcode:
    CS.Enter;
    try
      If Assigned(FOnNext) Then
        Syncronize(MessageNext);
    finally
      CS.Leave;
    end;
Aber man muss dann auch den Zugriff aus dem Hauptthread auf das Property "OnNext" mit CS schützen.
Damit würde aber in der Ereignisbehandlung "OnNext" im Hauptthread bei einem eventuellen Zugriff auf das Property "OnNext" des SaveThread ein Deadlock entstehen.

In der ursprünglichen Variante ist ein Schutz nicht notwendig, da auf FOnNext grundsätzlich nur im Hauptthread zugegriffen wird.
Ich denke es spricht hier aber nichts dagegen, auf "Assigned(FOnNext)" zusätzlich auch im Thread ohne CS zu prüfen, um unnötige Aufrufe von "Syncronize" zu vermeiden.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:35 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