![]() |
Threads und TBitmaps
Hallo,
ich möchte ein Program so abändern, dass CPU-lastige Grafikfunktionen von einem anderen Kern, also in einem Thread, abgearbeitet werden. Dabei soll in einem bestimmtem Interval das berechnete Bild(TBitmap) auf die Mainform(TImage) kopiert werden. Ich habe bis jetzt folgende Ansätze ausprobiert: 1. Das Bild wird von dem Thread auf die Mainform gezeichnet. 2. Die Mainform zeichnet das Bild durch Nachfrage an den Thread selbst. Das funkioniert kurzzeitig auch relativ gut, nur gibt es eben danach je nach Ansatz EOutofresource-Fehler(1) oder ein leeres Ergebnisbild(2), quasi zu einem zufälligen Zeitpunkt... Der EOutofresource-Fehler heißt meistens "Falscher Parameter". Der untere Quelltext ist ein einfaches Beispiel für die Basisfunktionen, die bei meinem Program gebraucht werden. Er erzeugt nach z.B. 1 Min die Fehlermeldung. procedure TPaintThread.Execute; begin while (Terminated = False) do begin if (MyBild = NIL) then begin randomize; MyBild := TBitmap.create; MyBild.Width := 1000; MyBild.Height := 1000; MyBild.Canvas.Brush.Color := clgreen; end else begin MyBild.Canvas.Rectangle(0, 0, random(500) + 1, random(500) + 1); Form1.Image1.Picture.Bitmap := MyBild; //Ansatz 1 end; sleep(1); end; end; Meine Frage ist nun, wie sich Zeichenoperationen auslagern lassen, ohne Fehlermeldungen auszulösen. |
AW: Threads und TBitmaps
Zunächst einmal darfst Du aus einem Thread heraus nicht auf den Canvas malen, also VCL-Operationen ausführen. Ergo kann dein Thread die Bitmaps nur neu berechnen. Zeichnen muss der Hauptthread
Du könntest einen Timer im Hauptthread starten, der alle 20ms Sekunden die Bitmap neu zeichnet (wenn sie sich verändert hat). Die Threads verändern nun irgendwann, von mir auch aus öfter als alle 20ms, das Bitmap und legen den Schalter 'Bitmap hat sich geändert' um. Der Hauptthread fragt den Schalter alle 20ms ab und zeichnet dann neu. Schalter und Bitmap müssen über Resourcenschutzblöcke (einer reicht) (TCriticalSection) gesichert werden. |
AW: Threads und TBitmaps
Die Ressourcen dürften bei dir schwinden, weil du ein Bitmap erzeugst (mit Create) aber am Ende der Procedure nicht frei gibst (Free). Das Bitmap hat mit den Dimensionen eine größe von 3MB. kannst ja ausrechnen, wie oft man ein Bitmap erzeugen kann, bis der Hauptspeicher aufgebraucht ist.
|
AW: Threads und TBitmaps
Sehe grade, daß du MyBild auf NIL testest. Mein Post hat sich also erledigt.
|
AW: Threads und TBitmaps
Liste der Anhänge anzeigen (Anzahl: 1)
Wenn es nur darum geht nach einem längerem Zeichenprozess das Bild in der MainForm darzustellen könnte man das auch so machen:
Delphi-Quellcode:
Angehängt ist ein kleines Projekt mit dem das läuft...
constructor TImageRenderer.Create;
begin inherited Create; fBmp := TBitmap.Create; fBmp.SetSize(100, 100); fBmp.PixelFormat := pf24Bit; end; destructor TImageRenderer.Destroy; begin fBmp.Free; inherited; end; procedure TImageRenderer.Execute; var ix: Integer; iy: Integer; begin while Not Terminated do begin fBmp.Canvas.Lock; for ix := 0 to 99 do begin for iy := 0 to 99 do begin fBmp.Canvas.Pixels[ix,iy] := RGB(Random(256),Random(256),Random(256)); end; Sleep(5); end; fBmp.Canvas.UnLock; Synchronize(PaintBmp); end; end; procedure TImageRenderer.PaintBmp; begin if assigned(fOnPaint) then begin fOnPaint(fBmp); end; end; |
AW: Threads und TBitmaps
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Whookie,
ich hab mir dein Projekt mal angesehen und es an Delphi 7 angepasst, starte ich es und drücke den Button so wird jedoch sofort eine Fehlermeldung(s. Anhang) ausgegeben :/ |
AW: Threads und TBitmaps
Ups ... Delphi 7 ... soweit ich weiß hat sich gerade in den Thread-Klassen einiges getan....
was hier das Problem ist, kann ich so leider nicht sagen... Ich würde dir empfehlen das ganze mal auszubauen und zu sehen wo das Problem liegt:
Delphi-Quellcode:
sollte mal laufen (aber erst mal ohne OnPaint zu verbinden)
procedure TImageRenderer.Execute;
var ix: Integer; iy: Integer; begin while Not Terminated do begin for ix := 0 to 99 do begin for iy := 0 to 99 do begin end; Sleep(5); end; Synchronize(PaintBmp); end; end; |
AW: Threads und TBitmaps
Tut mir Leid für die lange Zeitspanne bis zur Antwort,
ich habe mittlerweile herausgefunden, dass der Aufruf aus dem Thread heraus das Problem ist. Er soll auf der Form das Bild zeichnen, was zu dem Fehler führt. Wird im Thread jedoch nur die Berechnung der Threadeigenen Bitmap durchgeführt und diese durch die Form per Canvas.draw kopiert, so funktioniert es fehlerfrei. Zwar erzeugt das wiederum Auslastung, welche eigentlich im Thread sein sollte, jedoch scheint es sich nicht vermeiden zu lassen. Edit: Die Threadeigene Bitmap muss im Canvas unlocked werden, damit das Bild auf der Form nicht einfriert |
AW: Threads und TBitmaps
Hallo TheGroudonx,
man sollte auf jeden Fall den Canvas.lock und Canvas.unlock in einem Schutzblock fassen um die Ausgabe wieder freizugeben, die exklusiv für den Thread geblockt worden ist. Bei der Ausgabe sollte man bedenken, dass die Grafikausgabe vom BS gepuffert wird, dass bedeutet das wenn der Thread vor der Ausgabe schlafen gelegt wird, keine Ausgabe erfolgt. Mit der Function GdiFlush() kann die Ausgabe erzwungen werden. Bis bald Chemiker |
AW: Threads und TBitmaps
Hallo,
ich verzweifle so langsam an dem Thema Threads... zwar wird ein Bild ausgegeben, aber es gibt so viele mehr oder weniger zufällig auftretende Fehler... -Zuerst einmal funktioniert das Schritt-für-Schritt kompilieren des Threads nicht wirklich: Ein normal durchlaufender Thread bricht beim Schritt-für-Schritt durchgehen zufällig nach ung. 20 durchgängen ab und ist nichtmehr startbar, oder er gibt access violation messages wieder, die sonst nicht kämen, obwohl die Elemente existieren müssten. -Versuche ich eine Bitmap in ihrer Größe zu verändern, so kommt es dadurch zu einer EOutofrecource-Fehlermeldung. Selbst wenn man die Bitmap auf ihre eigene Größe anpasst, also keine Veränderung, geht das komplette Bild verloren - Was passiert denn da im Thread? Erzeugt er etwa jedesmal eine neue Bitmap, wenn man die Größe ändert, und müllt den Speicher mit den alten Kopien voll? -Letztendlich ist das Unlocken für mich noch relativ unklar...muss eine Bitmap bei jedem Zeichnen/Prozeduraufruf neu unlocked werden? Ein Projekt von mir Brach ab, obwohl nach dem Create alle Bitmaps unlocked wurden. Der Fehler lies sich nach Debuggen beheben, indem der unlockbefehl einer Bitmap nach create DOPPELT, also HINTEREINANDER!!!, geschrieben wurde. Das ganze Thema Threads scheint durch und durch voller Fehler zu stecken, es macht kaum Spaß sich den Weg aus denselben zu bahnen... Jedenfalls in meiner Delphi 7 Version. Wenn ihr Tipps zu den geschilderten Ereignissen habt die etwas Licht ins Dunkle bringen lasst es mich wissen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz