Einzelnen Beitrag anzeigen

Schwedenbitter

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

Rechenintensiven Thread aufräumen

  Alt 9. Nov 2014, 13:00
Ich habe ein Scanprogramm, dass die Bilder sofort verarbeitet und dem Benutzer Vorschläge für die beste Komprimierung machen soll. Für die Berechnung werden Threads verwendet. Das Komprimieren der Bilder (derzeit PNG und JPEG) erledige ich über den Code/die Units von Delphi. Und weil die Bilder größer sind, kann es manchmal dauern.
Wenn der Benutzer das Programm beendet, klappt das Dank Threads, hinterlässt aber Speicherlecks. Das gefällt mir natürlich nicht.

Der Code dazu sieht folgendermaßen aus:
Delphi-Quellcode:
Unit _CalcThread;

Interface

Uses
   System.Classes, Vcl.Graphics, Vcl.Imaging.pngimage, Vcl.Imaging.jpeg;

Type
   TCodecType   = (cdPNG, cdJPEG);
   TOnCalcDone   = Procedure(Codec: TCodecType; Size: Int64) Of Object;
   TCalcThread   = Class(TThread)
                 Private
                     fSize         : Int64;
                     fCodec      : TCodecType;
                     fBitmap      : TBitmap;
                     fOnCalcDone   : TOnCalcDone;
                     Procedure EventOnCalcDone;
                 Public
                     Constructor Create(Codec: TCodecType; Bitmap: TBitmap;
                        OnCalcDone: TOnCalcDone);
                     Procedure Execute; Override;
                     Destructor Destroy; Override;
                 End;

Implementation

// Absicherung des Eriegnis-Aufrufs --------------------------------------------
Procedure TCalcThread.EventOnCalcDone;
Begin
   If Assigned(fOnCalcDone) Then                     // Sicherheitsprüfung
      FOnCalcDone(fCodec, fSize);                  // Ereignis auslösen
End;

// Ein Thread wird erstellt ----------------------------------------------------
Constructor TCalcThread.Create(Codec: TCodecType; Bitmap: TBitmap;
   OnCalcDone: TOnCalcDone);
Begin
   fSize:= -1;                                 // ungültigen Wert vorgeben
   fCodec:= Codec;                              // Codec merken
   fOnCalcDone:=OnCalcDone;                        // Zeiger auf Ereignis merken
   fBitmap:=TBitmap.Create;                        // TBitmap anlegen
   fBitmap.Assign(Bitmap);                           // Bild kopieren
   FreeOnTerminate:=True;                           // Speicher selbst freigeben

   Inherited Create(True);                           // Thread erstellen
   Priority:= tpIdle;                        // geringe Priorität
//   Resume;                                          // "Start" löst Exception aus!
   Start;                                       // "Resume" ist veraltet
End;

// Der eigentliche Thread (=die Berechnung) ------------------------------------
Procedure TCalcThread.Execute;
Var
   lMemStream      : TMemoryStream;
Begin
   lMemStream:=TMemoryStream.Create;               // Nur im Speicher arbeiten
   Try
      Case fCodec Of
         cdPNG   :   With TPngImage.Create Do         // temp. PNG-Objekt anlegen
                  Try
                     Filters:=[pfNone, pfSub, pfUp, pfAverage, pfPaeth];
                     CompressionLevel:=9;            // Maximale Kompression
                     Assign(fBitmap);               // Bilddaten übernehmen
                     SaveToStream(lMemStream);      // virtuell abspeichern
                     fSize:=lMemStream.Size;         // Größe merken
                  Finally
                     Free;                           // PNG-Objekt freigeben
                  End;
         cdJPEG:   With TJPEGImage.Create Do         // tenp. JPEG-Objekt anlegen
                  Try
                     CompressionQuality:=80;         // 100 = max, 1 = min
                     Assign(fBitmap);               // Bilddaten übernehmen
                     SaveToStream(lMemStream);      // virtuell abspeichern
                     fSize:=lMemStream.Size;         // Größe merken
                  Finally
                     Free;                           // JPEG-Objekt freigeben
                  End;
      End;
   Finally
      lMemStream.Free;                              // TMemoryStream freigeben
      Synchronize(EventOnCalcDone);                  // Das Ende mitteilen
   End;
End;

// Der Thread wird beendet -----------------------------------------------------
Destructor TCalcThread.Destroy;
Begin
   fBitmap.Free;                                    // TBitmap selbst freigeben
   fOnCalcDone:=nil;                                 // Zeiger löschen
   Inherited;                                       // den Rest ausführen
End;

End.
Da der Code unter Execute sehr kurz ist, macht es keinen Sinn auf Terminated zu reagieren.

Zusatzfrage:
Der Compiler sowie die Hilfe sagen mir, TThread.Resume; sei veraltet. Allerdings erzeugt TThread.Start; bei mir immer eine Exception vom Typ EInvalidPointer . Und was noch schlimmer ist: bevor ich die Message dazu erhalte, zeigt mir Windows 8.1 an "Das Programm ... funktioniert nicht mehr richtig. Online nach einer Lösung suchen...". Der Debugger stürzt ab, die exe-Datei lässt sich nicht mehr löschen und damit neu compilieren.

Wie löse ich diese Probleme?

Gruß, Alex
Alex Winzer
  Mit Zitat antworten Zitat