Delphi-PRAXiS
Seite 1 von 8  1 23     Letzte » 

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Threads und TBitmaps (https://www.delphipraxis.net/181416-threads-und-tbitmaps.html)

TheGroudonx 12. Aug 2014 12:37

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.

Dejan Vu 12. Aug 2014 13:37

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.

bernau 12. Aug 2014 14:00

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.

bernau 12. Aug 2014 14:03

AW: Threads und TBitmaps
 
Sehe grade, daß du MyBild auf NIL testest. Mein Post hat sich also erledigt.

Whookie 12. Aug 2014 14:21

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:
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;
Angehängt ist ein kleines Projekt mit dem das läuft...

TheGroudonx 12. Aug 2014 15:53

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 :/

Whookie 12. Aug 2014 18:31

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:
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;
sollte mal laufen (aber erst mal ohne OnPaint zu verbinden)

TheGroudonx 30. Aug 2014 23:59

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

Chemiker 31. Aug 2014 10:18

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

TheGroudonx 1. Sep 2014 11:42

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 20:57 Uhr.
Seite 1 von 8  1 23     Letzte » 

Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf