Autor Beitrag
HenryHux
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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?
ausblenden 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
ausblenden Delphi-Quelltext
1:
ImgLst.GetBitmap;					


Lg
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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. :nixweiss:

_________________
We are, we were and will not be.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 25.02.11 13:32 
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 25.02.11 17:22 
Ich habe echt keine Idee mehr, wo das Problem liegen könnte.
So sieht bei mir alles aus
ausblenden volle Höhe Delphi-Quelltext
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);  //hier werden positionen festgelegt, wo er der screenshot macht, brauch auf keine fall ne synchronisierung

    ComparePicture:=Tbitmap.create;
    TargetBmp := TBitmap.Create;

    Thread[T].ScreenshotSynched(Rect(Links,Oben,Links+100,Oben+100),      // hier macht er den screenshot. kann sein, dass hier schon der fehler liegt, prozedur steht unten
                                          32,43,64,90, TargetBmp);        //das Thread[t] ist der aktuell laufende thread

    for i := 1 to 20 do
    begin
      GUI.CardsImgLst.GetBitmap(i-1, ComparePicture);
      if CompareImages(TargetBmp, ComparePicture) then      //hier werden bilder verglichen, ist nicht snychonisiert, vlt liegt auch hier der fehler
      begin
        if (i>0and (i<20then
        begin
          Result := i;
          exit();
        end;
      end;
    end;
  finally
    FreeAndNil(TargetBmp);
    freeandnil(ComparePicture);
  end;
end;

ausblenden volle Höhe Delphi-Quelltext
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, 00, 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  //habe ein record, mit welchem ich die variablen an die zu synchronisierende prozedur weitergebe, ist unter private eingetragen
    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
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Fr 25.02.11 17:47 
Da ist doch das, was jaenicke auch sagte:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
begin
  try
    with SynchP do  //habe ein record, mit welchem ich die variablen an die zu synchronisierende prozedur weitergebe, ist unter private eingetragen
    begin
      TargetBmp := TBitmap.Create;
      Bounds := Bounds2;

Du erzeugst/verwendest im Kontext eines Threads ein Bitmap. Das ist Böhse(tm). :mahn:

_________________
We are, we were and will not be.

Für diesen Beitrag haben gedankt: HenryHux
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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? :D

Lg
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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. :D

_________________
We are, we were and will not be.
HenryHux Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 25.02.11 18:44 
Nein, leider war es das nicht :(
Ich werde also weitersuchen.

Lg
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 25.02.11 19:00 
Das Problem liegt wohl vor allem hier:
user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: Fr 25.02.11 20:06 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das Problem liegt wohl vor allem hier:
user profile iconHenryHux hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden 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.


Ha, das hab ich mir irgendwie schon die ganze Zeit gedacht :D

Habe es so gemacht, mit IPC kenn ich mich kaum aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TProcess.GetMiscImgLstSynched(pos : integer; var bmp : TBitmap);
begin
  MiscL.Nr := Pos;
  Synchronize(GetMiscImgLst);
  bmp.Assign(MiscL.Bmp);
end;

procedure TProcess.GetMiscImgLst;
begin
  GUI.MiscImgLst.GetBitmap(MiscL.Nr, MiscL.Bmp);
end;


Dürfte das so klappen?

Lg
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 542
Erhaltene Danke: 33

Windows 7 Premium
Delphi XE, Eclipse
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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.