Autor |
Beitrag |
HenryHux
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Do 24.02.11 23:01
Hi, bin immoment auf Fehlersuche, weiß aber echt nicht wo der Fehler liegt.
Ich wollte mal Fragen, was man denn so alles in Threads synchronisieren muss.
Gehört sowas dazu?
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| If CompareMem (Bitmap1.Scanline[Bitmap1.Height - 1], Bitmap2.ScanLine [Bitmap2.Height - 1], Bitmap1.Width*Bitmap1.Height*SizeOf(TRGBTriple)) Then Result := true Else Result := false; |
Oder ImageLists? zb
Delphi-Quelltext
Lg
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Do 24.02.11 23:05
Solange Bitmap1 und Bitmap2 im Thread erzeugt wurden, kann das auch ohne funktionieren. Denn hier greifst du ja nur auf den Speicher zu.
Grundsätzlich ist alles was mit visueller Darstellung zu tun hat, also auch das Zeichnen auf eine Bitmap, potentiell gefährlich in Threads. Spätestens, wenn du in einem Thread eine Bitmap erzeugst und in einem anderen drauf zugreifst, knallt es.
|
|
Sinspin
      
Beiträge: 1335
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Fr 25.02.11 11:56
Was genau bekommst Du denn für einen Fehler? Eine Schutzverletzung?
Wenn Du den Speicher einer (hier der letzten) Bitmapzeile vergleichen willst dann darfst du als Byteanzahl auch nur die Länge einer Zeile angeben und nicht die des gesammten Bitmaps. Geht es Dir ums ganze Bild brauchst Du Scanline[0] als Zeiger auf die Bitmaps.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 25.02.11 12:15
Ich habe die Erfahrung gemacht, dass Bitmaps in Threads generell gefährlich sind. Selbst wenn Bitmaps nur innerhalb eines Threads erstellt, benutzt und wieder zerstört werden, können merkwürdige Dinge passieren.
Woran das genau liegt, weiß ich nicht. 
_________________ We are, we were and will not be.
|
|
Sinspin
      
Beiträge: 1335
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Fr 25.02.11 12:50
Innerhalb eines Threads hatte ich bisher nie Probleme, aber wenn man ein Bitmap Threadübergreifend verwendete rumpelt es hin und wieder, komischweise selbst mit Synchronisation. Ich arbeite daher immer mit selber reservierten Speicherblöcken. Zum speichern oder laden lege ich mir kurz ein Bitmap an.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.02.11 13:32
Sinspin hat folgendes geschrieben : | aber wenn man ein Bitmap Threadübergreifend verwendete rumpelt es hin und wieder, komischweise selbst mit Synchronisation. |
Eine Bitmap, auf deren HDC du (mit Canvas z.B.) zugreifst, muss immer im Hauptthread erstellt werden und darf auch nur dort benutzt werden (synchronisiert eben). Wenn sowohl die Erstellung als auch die Zugriffe synchronisiert passieren, sollte es funktionieren.
Bei Zugriffen mit ScanLine bin ich mir nicht wirklich sicher, würde aber auch davon abraten die im Thread zu versuchen.
|
|
bummi
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Fr 25.02.11 14:59
Zugriffe aus Threads scheinen sicher zu sein wenn man sie mit Canvas.Lock / canvas.Unlock kapselt, ob das sinnvoll ist mag dahingestellt sein.
_________________ Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 25.02.11 17:22
Ich habe echt keine Idee mehr, wo das Problem liegen könnte.
So sieht bei mir alles aus
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:
| var i : Integer; comparepicture : TBitmap; TargetBmp : TBitmap; begin result := 0; try SetPositions(links,oben,links,oben, T); ComparePicture:=Tbitmap.create; TargetBmp := TBitmap.Create;
Thread[T].ScreenshotSynched(Rect(Links,Oben,Links+100,Oben+100), 32,43,64,90, TargetBmp); for i := 1 to 20 do begin GUI.CardsImgLst.GetBitmap(i-1, ComparePicture); if CompareImages(TargetBmp, ComparePicture) then begin if (i>0) and (i<20) then begin Result := i; exit(); end; end; end; finally FreeAndNil(TargetBmp); freeandnil(ComparePicture); end; end; |
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:
| procedure TProcess.Screenshot; var DesktopHandle: HDC; ShotTargetBitmap : TBitmap; begin if not Assigned(SynchP.TargetBmp) then Exit; Shottargetbitmap := TBitmap.Create; try ShotTargetbitmap.Width := SynchP.Bounds.Right - SynchP.Bounds.Left; ShotTargetbitmap.Height := SynchP.Bounds.Bottom - SynchP.Bounds.Top; SynchP.TargetBmp.Width := SynchP.Rechts - SynchP.Links; SynchP.TargetBmp.Height := SynchP.Unten - SynchP.Oben; DesktopHandle := GetDC(0); try BitBlt(ShotTargetBitmap.Canvas.Handle, 0 ,0, SynchP.bounds.Right-SynchP.bounds.left, SynchP.bounds.Bottom - SynchP.bounds.top, DesktopHandle, SynchP.bounds.Left, SynchP.bounds.Top,SRCCOPY); BitBlt(SynchP.TargetBmp.Canvas.Handle, 0, 0, SynchP.Rechts, SynchP.Unten, ShotTargetBitmap.Canvas.Handle, SynchP.Links, SynchP.Oben, SRCCOPY); finally ReleaseDC(0, DesktopHandle); end; finally FreeAndNil(ShotTargetBitmap); end; end;
procedure TProcess.ScreenshotSynched(Bounds2:TRect; Links2, Rechts2, Oben2, Unten2 : Integer; var Bmp : TBitmap); begin try with SynchP do begin TargetBmp := TBitmap.Create; Bounds := Bounds2; Links := Links2; Rechts := Rechts2; Oben := Oben2; Unten := Unten2; end; SYNCHRONIZE(ScreenShot); Bmp.Assign(SynchP.TargetBmp); finally SynchP.TargetBmp.free; end; end; |
Hier ist dann die Funktion ums zu vergleichen
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| If CompareMem (Bitmap1.Scanline[Bitmap1.Height - 1], Bitmap2.ScanLine [Bitmap2.Height - 1], Bitmap1.Width*Bitmap1.Height*SizeOf(TRGBTriple)) Then Result := true Else Result := false; |
Wie gesagt, ein Thread läuft.
Bei 2 läuft er auch, aber alles andere als stabil und fehlerfrei.
Wenn irgendjemandem was spontan beim überfliegen auffällt, kann er es ja gerne schreiben =)
Danke und Liebe Grüße
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 25.02.11 17:47
Da ist doch das, was jaenicke auch sagte:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| begin try with SynchP do begin TargetBmp := TBitmap.Create; Bounds := Bounds2; |
Du erzeugst/verwendest im Kontext eines Threads ein Bitmap. Das ist Böhse(tm). 
_________________ We are, we were and will not be.
Für diesen Beitrag haben gedankt: HenryHux
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 25.02.11 18:22
Ok, geändert.
Doch das dürfte doch nicht das Problem verursachen, das ich suche oder ist da was an mir vorbeigegangen, was man über TBitmaps wissen sollte?
Lg
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 25.02.11 18:35
Doch, das könnte schon sein. Ich hatte auch mal ein Programm, das in einem Thread ein Bitmap bemalt und das dann synchronisiert in ein Image gepackt hat. Das Ding lief prima - solange man die Maus nicht bewegt hat.
Bitmap aus dem Thread raus, und das Problem war erledigt. 
_________________ We are, we were and will not be.
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 25.02.11 18:44
Nein, leider war es das nicht
Ich werde also weitersuchen.
Lg
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.02.11 19:00
Das Problem liegt wohl vor allem hier: HenryHux hat folgendes geschrieben : | Delphi-Quelltext 1:
| GUI.CardsImgLst.GetBitmap(i-1, ComparePicture); | |
Du greifst hier offenbar nicht nur auf eine ImageList zu, sondern das auch noch unsynchronisiert. Das kann nicht gutgehen.
Denn GetBitmap führt sogar Zeichenoperationen aus soweit ich mich erinnere.
Ich hätte da eine andere Lösung für dich:
Lagere die Prüfung nicht nur in einen eigenen Thread, sondern in einen anderen Prozess aus. Via IPC bekommst du dann das Ergebnis mitgeteilt und gut ist es. Dann sind die ganzen Synchronisierungsprobleme vom Tisch.
Für diesen Beitrag haben gedankt: HenryHux
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Fr 25.02.11 20:06
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 25.02.11 21:19
Wenn die Bitmaps alle im Hauptthread erzeugt werden, kann das so gehen, ja. Dann stellt sich aber die Frage was dir der Thread bringt, wenn als Zugriffe eh synchronisiert werden.
Deshalb rate ich wirklich zu einem neuen Prozess, der dann wirklich alles machen kann und dennoch vollkommen parallel laufen kann.
|
|
HenryHux 
      
Beiträge: 542
Erhaltene Danke: 33
Windows 7 Premium
Delphi XE, Eclipse
|
Verfasst: Sa 26.02.11 01:12
Du hast ja IPC angesprochen.
Wie kann ich denn damit sowas realisieren?
Mir würde nur einfallen, einen Thread zu erzeugen, auf welchen dann gewartet werden müsste, denn ohne das Ergebnis gehts ja nicht weiter. Als Schlagwörter würden mir da Pipes und MemoryMapping einfallen, aber wie gesagt ich weiß nicht wie man mit sowas effektiv umgeht.
Lg
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 26.02.11 03:35
Wenn es nur um einen Integerwert als Rückgabewert geht, kannst du auch einfach den ExitCode in dem neuen Prozess zuweisen und im alten mit CreateProcess arbeiten und im Thread mit WaitForMultipleObjects auf die Beendigung warten.
Danach kannst du den ExitCode des Prozesses mit GetExitCodeProcess abfragen.
|
|
|