Delphi-PRAXiS
Seite 5 von 8   « Erste     345 67     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)

Medium 1. Sep 2014 17:28

AW: Threads und TBitmaps
 
Was für Fehler kommen da? Bist du sicher, dass die nicht damit zusammen hängen, dass du da reichlich Speicherlecks produzierst? Oder mit dem Abspeichern?

Bummi 1. Sep 2014 17:36

AW: Threads und TBitmaps
 
Liste der Anhänge anzeigen (Anzahl: 4)
@Medium danke für den Hinweis auf das fehlende Free, aber damit hat es nicht zu tun, wenn du die Bitmaps anschaust siehst Du was ich meine.

Whookie 1. Sep 2014 20:44

AW: Threads und TBitmaps
 
Also auch das Beispiel geht bei mir einwandfrei...


Delphi-Quellcode:
procedure TTestThread.Execute;
var
 bmp :TBitmap;
 i:Integer;
begin
   bmp :=TBitmap.Create;
   bmp.Canvas.Lock;
   bmp.Width := 100;
   bmp.Height := 100;
   bmp.Canvas.Pen.Color := clBlue;
   for I := 0 to 100 do
   begin
     bmp.Canvas.MoveTo(0,0);
     bmp.Canvas.LineTo(100,i);
   end;
   bmp.SaveToFile('C:\temp\test\' + Ffn );
   bmp.Free;
end;
mit 200 Threads probiert (auch wenn des sinnbefreit ist..)

TheGroudonx 3. Sep 2014 12:38

AW: Threads und TBitmaps
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Whookie (Beitrag 1270582)
...wie gesagt wenn du korrekt lockst/unlockst geht das (zumindestens bei mir unter xe5) problemlos...


Delphi-Quellcode:
procedure TPaintThread.Execute;
begin
 While (Terminated = False) do
 begin
   MyBild.Canvas.lock;
   Original.Canvas.Lock;
   try
     MyBild.Width := random(500) + 500;
     MyBild.Height := random(500) + 500;
     MyBild.Canvas.Draw(random(25) + 1, random(25) + 1, Original);
     MyBild.Canvas.Rectangle(random(25) + 1, random(25) + 1, random(50) + 25, random(50) + 25);
   finally
     MyBild.Canvas.unlock;
     Original.Canvas.Unlock;
   end;
   Synchronize(Zeichnen);
 end;
end;

Ich musste leider feststellen, dass, wenn man diesen Code eine Weile durchsteppen lässt, es zu einer EAccessviolation kommt.
Diese findet allerdings nicht im Threadablauf, sondern im Prozess der Hauptform statt, während das Bild per Synchronize gezeichnet wird.
Diese EAccessViolation findet sogar dann statt, wenn man den Code so abändert:
Delphi-Quellcode:
procedure TPaintThread.Execute;
begin

 While (Terminated = False) do
 begin

  try

  Synchronize(Zeichnen);

  finally

  end;


 sleep(1);
 
 end;
end;



procedure TPaintThread.Zeichnen;
begin
//
end;
Das bedeutet, dass allein das Aufrufen der (leeren) Synchronize-Methode einen EAccess-Error hervorruft, zumal nichts anderes der Auslöser sein kann.
Versteht ihr, was da schief läuft?
(Der Fehler kommt oft nach einigen Sekunden, manchmal aber auch garnicht)

TheGroudonx 3. Sep 2014 12:58

AW: Threads und TBitmaps
 
Ich habe das jetzt nochmal erweitert getestet und festgestellt, dass es nicht an der Snchronize-Methode liegt.
JEDE Kommunikation von MainForm zu Thread per Prozedur kann (nach 10-100 Aufrufen im Mittel) diese Access-Violation beim Durchsteppen auslösen.
Was ich mich jetzt frage ist:
-Wieso kommt es dazu?
-Lässt es sich vermeiden? (Vermutlich nicht)
-Hat die Fehlermeldung beim Durchsteppen auch Relevanz beim normalen Ablauf des Programms?
:?

Sir Rufo 3. Sep 2014 13:36

AW: Threads und TBitmaps
 
Also wir müssen uns hier auf eine korrekte Sprache einigen, denn sonst weiß keiner was wirklich gemeint ist. Beim Thema Multithreading ist das einfach unerlässlich.

Es kommt immer auf den Thread-Kontext an.

Wenn du also bei irgendetwas im Bereich Multithreading Probleme hast, dann ist es sehr wichtig, dass du dabei den Thread-Kontext mit angibst, und nicht welche Form da was aufruft.

Auch die Methode einer Form kann in jedem beliebigen Thread-Kontext aufgerufen werden, niemand hindert dich daran. Greifst du in irgendeinem Thread-Kontext <> MainThread-Kontext auf die VCL zu, dann kann es rummsen - das ist ja das Gemeine, es rummst nicht immer ;)

Den aktuellen Thread-Kontext fragt man ganz einfach mit
Delphi-Quellcode:
TThread.CurrentThread.ThreadID
ab (bei Delphi 7 war das
Delphi-Quellcode:
GetCurrentThreadID
oder so) und den MainThread-Kontext mit
Delphi-Quellcode:
MainThreadID
. Sind die beiden Werte unterschiedlich, dann ist man eben nicht im MainThread-Kontext.

TheGroudonx 3. Sep 2014 13:55

AW: Threads und TBitmaps
 
Zitat:

Zitat von Sir Rufo (Beitrag 1270886)
Also wir müssen uns hier auf eine korrekte Sprache einigen, denn sonst weiß keiner was wirklich gemeint ist.

Es kommt immer auf den Thread-Kontext an.

Wenn du also bei irgendetwas im Bereich Multithreading Probleme hast, dann ist es sehr wichtig, dass du dabei den Thread-Kontext mit angibst, und nicht welche Form da was aufruft.
Delphi-Quellcode:
MainThreadID
. Sind die beiden Werte unterschiedlich, dann ist man eben nicht im MainThread-Kontext.

Ich nahm an, dass bei einer Kombination aus dem üblichen Mainform-Prozess und einem Thread keine Verwechslungen durch Vokalwahl auftreten könnten.
Meines Wissens führt der Thread alles selbstständig aus, was über seine Routine Execute verbunden ist und kein Synchronize ist.

Jedenfalls ruft der Hauptprozess eine leere Methode des Threads auf, was zu einem Fehler führt. (siehe oben!)

Sir Rufo 3. Sep 2014 14:01

AW: Threads und TBitmaps
 
Zitat:

Zitat von TheGroudonx (Beitrag 1270892)
Jedenfalls ruft der Hauptprozess eine leere Methode des Threads auf, was zu einem Fehler führt. (siehe oben!)

Es gibt ja nur einen Prozess und innerhalb dessen mehrere Threads.

Also wer ruft jetzt in welchem Thread-Kontext was auf?

Delphi-Quellcode:
procedure TPaintThread.Execute;
begin
  While (Terminated = False) do
  begin
    try
      Synchronize( Zeichnen );
    finally
    end;
    sleep(1);
  end;
end;

procedure TPaintThread.Zeichnen;
begin
  // 
end;
PS
Wenn die
Delphi-Quellcode:
TPaintThred.Execute
Methode im MainThread-Kontext aufgerufen wird (weil du diese Methode direkt aufrufst), dann ist es kein Wunder, dass du da Probleme bekommst, denn vom MainThread-Kontext aus
Delphi-Quellcode:
Synchronize
aufrufst, dann kann das zu Problemen führen, wie es auch in der Dokumentation angegeben ist.

TheGroudonx 3. Sep 2014 14:15

AW: Threads und TBitmaps
 
Der normale Mainthread-Context erstellt den Thread(TThread)-von da aus läuft alles von selbst weiter.
Der Thread(TThread) ist in einer separaten Unit.
Er(Der Thread) arbeitet seine Execute Methode ab.
Dabei ruft er die Synchronize(Zeichnen) Prozedur auf, durch welche der Mainthread-Context die Zeichen-Routine ausführt.
Dies führt nach Wiederholungen beim Durchsteppen zu einem EAccess-Violation Fehler.
Dieser Fehler passiert, da die Zeichenmethode per Synchronize aufgerufen wird, im Mainthread-Context, wobei die Abbruchstelle am Ende der Zeichenroutine(leer) in der Thread-Unit ist.

Sir Rufo 3. Sep 2014 14:27

AW: Threads und TBitmaps
 
Kann ich so nicht nachvollziehen, läuft wie erwartet

EDIT Überwachung des Thread-Kontexts
Delphi-Quellcode:
unit PaintThread;

interface

uses
  Classes;

type
  TPaintThread = class( TThread )

  private
    procedure Zeichnen;
  protected
    procedure Execute; override;
  end;

implementation

uses
  SysUtils,
  Windows;

{ TPaintThread }

procedure TPaintThread.Execute;
begin

  if MainThreadID = GetCurrentThreadId
  then
    raise Exception.Create( 'Upps, ich darf nicht im MainThread-Kontext sein!' );

  inherited;
  while not Terminated do
    begin
      Synchronize( Zeichnen );
      Sleep( 1 );
    end;
end;

procedure TPaintThread.Zeichnen;
begin
  if MainThreadID <> GetCurrentThreadId
  then
    raise Exception.Create( 'Upps, ich bin nicht im MainThread-Kontext!' );

end;

end.
Delphi-Quellcode:
unit FormMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics,
  Controls, Forms, Dialogs,
  PaintThread;

type
  TForm1 = class( TForm )
  private
    FPaintThread : TPaintThread;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}
{ TForm1 }

procedure TForm1.AfterConstruction;
begin
  inherited;
  FPaintThread := TPaintThread.Create( False );
end;

procedure TForm1.BeforeDestruction;
begin
  inherited;
  FPaintThread.Free;
end;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:27 Uhr.
Seite 5 von 8   « Erste     345 67     Letzte »    

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