Autor |
Beitrag |
Visum
      
Beiträge: 106
|
Verfasst: So 28.12.08 21:06
Mahlzeit!
Ich hab folgendes Problem: Ich habe mehrere Threads und zu jedem Thread ein TImage, auf dem die Threads eine Art Status ausgeben sollen.
Dazu soll in dem Image idealerweise ein animiertes Gif ausgegeben werden.
Dazu muss das ganze wenn ich das richtig verstanden habe synchronisiert werden. Das Problem ist, dass dieses Synchronize jedesmal hängen bleibt. Ich würde vermuten, dass dies dadurch kommt, dass bei TGifImage ein eigener Thread erzeugt wird (zum animieren) und das Synchronize auf eben diesen Thread wartet, mit (logischerweise nicht animierten) Jpeg funktioniert das ganze nämlich.
Kann mir jemand sagen, ob meine Vermutung soweit richtig ist? Und noch besser .. wie ich das ganze realisieren kann?
Gruß,
visum
_________________ Was blubbert kommt in den Teich!
|
|
Xentar
      
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: So 28.12.08 21:13
Code?
Ich glaub nicht, dass das Synchronize hängen bleibt, wenn du nur ein anderes Bild zuweist.
_________________ PROGRAMMER: A device for converting coffee into software.
|
|
Visum 
      
Beiträge: 106
|
Verfasst: So 28.12.08 21:56
Also .. erstmal ein wenig Code, ich hoffe er ist einigermaßen lesbar ..
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66:
| type TMyThread = class(TThread) private pic1 : TGifImage; pic2 : TGifImage; PaintTo : TImage; p : boolean; public procedure updp; constructor create(startsuspended : boolean; PaintTo : TImage); protected procedure Execute; override; end;
type TForm1 = class(TForm) Image1: TImage; Button1: TButton; procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyThread.create(startsuspended : boolean; PaintTo : TImage); begin pic1 := TGifImage.Create; pic2 := TGifImage.Create; pic1.LoadFromFile('1.gif'); pic2.LoadFromFile('2.gif'); self.PaintTo := PaintTo; p := true; inherited Create(startsuspended); end;
procedure TMyThread.updp; begin if p then paintto.Picture.Assign(pic1) else paintto.Picture.Assign(pic2); end;
procedure TMyThread.Execute; begin while(true) do begin synchronize(self.updp); p := not p; sleep(1); end; end;
var MyThread : TMyThread;
procedure TForm1.Button1Click(Sender: TObject); begin MyThread := TMyThread.create(false,Image1); end; |
Wie gesagt, wenn ich Gif gegen Jpeg ersetze funktioniert das ganze. Wenn ich im Gif die Animationen deaktiviere funktioniert das ganze auch.
Interessant wären halt die Animationen (die Bilder sollen im tatsächlichen Programm nicht so hektisch geändert werden wie hier in dem Beispiel).
Moderiert von Narses: Code- durch Delphi-Tags ersetzt
_________________ Was blubbert kommt in den Teich!
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: So 28.12.08 22:39
Ich hatte mal ähnliche Probleme mit sowas. Ursache: Bitmaps etc. sind nicht Threadsafe. D.h.: Ein Bitmap in einem Thread erzeugen und dann rüberschaufeln auf ein Image is nich. Da hilft auch synchronize nicht. Woran das genau liegt, habe ich noch nicht verstanden - das kann evtl. jemand anders erklären. Hat wohl irgendwas mit den Handles oder so zu tun. Das geht mal gut, und mal gehts schief. Bei mir ist es schief gegangen, sobald man die Maus bewegte.
Lösung: Liefere der VCL Rohdaten, damit die sich komplett um das Zeichnen kümmern kann. Zur Not das Bitmap im Thread in einen Stream schreiben, und von der VCL aus diesem Stream das Bitmap wieder laden.
_________________ We are, we were and will not be.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: So 28.12.08 23:35
@Gausi: Mit non-VCL Code sind Bitmaps kein Problem.
@Visum: Synchronize bleibgt wohl hängen, weil der MainThread beschäftigt ist. Die synchronisierten Blöcke werden im Main Loop abgearbeitet, d.h. während einer langen Rechnung wird da nichts passieren.
TGifImage kenn ich nicht, aber wenn der nicht fast ausschliesslich WinAPI Code enthält wird das wohl kaum funktionieren.
|
|
Visum 
      
Beiträge: 106
|
Verfasst: Mo 29.12.08 02:28
@Gausi: Die Klasse TGifImage (über Torry gefunden) verwaltet Gif-Images. Zur Animation verwendet das Objekt einen eigenen Thread. Das funktioniert soweit ich das nachvollziehen kann auch. Von daher hoffe ich nicht, dass du recht hast, das würde die Klasse auf ziemlich wacklige Beine stellen
@Delfiphan: Der Main-Thread ist wie im von mir geposteten Code. Um es kurz zu fassen: Er berechnet nichts. Sämtliche Arbeit wird von den Threads übernommen. Von daher dürfte die Synchronisation nicht wirklich ein Problem sein.
Wie ich bereits erwähnt habe, gehe ich davon aus, dass das Problem darin liegt, dass das Synchronize darauf wartet, dass der von den Gif-Images erzeugt Thread terminiert und erst dann die Synchonisation weiterführt. Meiner Logik nach stützen alle Tests, die ich durchgeführt habe dies.
Ich werd morgen mal einen Ansatz über Semaphore testen und sollte das nicht klappen die ganze Zeichnerei auf einen eigenen Thread zu verlagern, sodass jeder Thread, der was Ausgeben will, das einfach einreiht und der eine Thread das ganze dann abarbeitet.
Ich meld mich wieder, wenn ich was neues weiß.
Gruß
vis
_________________ Was blubbert kommt in den Teich!
|
|
jaenicke
      
Beiträge: 19314
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 29.12.08 03:42
Visum hat folgendes geschrieben : | Wie ich bereits erwähnt habe, gehe ich davon aus, dass das Problem darin liegt, dass das Synchronize darauf wartet, dass der von den Gif-Images erzeugt Thread terminiert und erst dann die Synchonisation weiterführt. Meiner Logik nach stützen alle Tests, die ich durchgeführt habe dies. |
So funktioniert Synchronize aber nicht. Synchronize führt das, was es durchführen soll, im Kontext des Hauptthreads aus. D.h. du lädst die im Thread erzeugten TGifImages in das TImage. Erzeugt wurden die aber im Thread. Du sagtest ja das Zeichnen würde wiederum in einem Thread geschehen. Was wenn der jetzt keine Synchronisation mit dem Hauptthread sondern mit deinem anderen Thread durchführt?
So genau weiß ich nicht wie das intern dann abläuft, aber die TGifImage Objekte wurden ja im Kontext deines Threads erzeugt, und deren Zeichenthread greift ja auf Code davon zu...
Visum hat folgendes geschrieben : | Ich werd morgen mal einen Ansatz über Semaphore testen und sollte das nicht klappen die ganze Zeichnerei auf einen eigenen Thread zu verlagern, sodass jeder Thread, der was Ausgeben will, das einfach einreiht und der eine Thread das ganze dann abarbeitet. |
Am besten wäre es vielleicht, wenn du eine Verwaltungsklasse erzeugst, die dann einen Dateinamen übergeben bekommt, welches Bild geladen werden soll. Ist das Bild noch nicht geladen, dann wird es geladen, ansonsten wird das bereits geladene Bild benutzt. Dafür werden einmal geladene Bilder zwischengespeichert.
Aus dem Thread kannst du dann einfach den Dateinamen angeben, und trotzdem werden die Bilder nach dem ersten Laden zwischengespeichert. Trotzdem werden aber die TGifImages im Hauptthread erstellt, was das Problem lösen sollte.
|
|
|