Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Probleme mit Thread in eigener Komponente (https://www.delphipraxis.net/68198-probleme-mit-thread-eigener-komponente.html)

Sascha L 26. Apr 2006 07:56


Probleme mit Thread in eigener Komponente
 
Hallo,

ich habe eine eigene Komponente entwickelt, die auch einwandfrei funktioniert. Leider darf ich den Code nicht veröffentlichen, aber das spielt auch keine Rolle, da die Komponente ja fehlerfrei funktioniert.

Mithilfe eines Timers wurde jede Millisekunde eine Prozedur aufgerufen. Bei verschiedenenen Tests auf unterschiedlichen PCs viel auf, dass das ganze nicht immer performant ist, da es sein kann, dass die Prozedur länger als 1ms brauch und das hat ja zur Folge, dass alles Andere hinten dran in eine Warteschlange gesetzt wird und dann schnellt die CPU-Auslastung nach oben.

Also habe ich nun alles so umgebaut, dass ich einen Thread verwende.

Hier mal ein kleiner Auszug:

Delphi-Quellcode:
type
  TDrawThread = class(TThread)
  private
    fOwner: TObject;
    protected
      procedure Execute; override;
      procedure Delay(msec: Longint);
    public
      constructor Create(AOwner: TObject);
    end;

TTicker = class(TGraphicControl)
  private
  fDrawThread: TDrawThread;

[...]

constructor TDrawThread.Create(AOwner: TObject);
begin
  fOwner := AOwner;
  inherited Create(true);
end;

procedure TDrawThread.Execute;
begin
  while not Terminated do begin
    with (fOwner as TTicker) do begin
      fTick := fTick + 1;
      if fTick > 10000 then fTick := 0;
      DrawEntries;
    end;
    Delay(1);
    //Sleep(1);
  end;
end;

procedure TDrawThread.Delay(msec: Longint);
var
  start, stop: Longint;
begin
  start := GetTickCount;
  repeat
    stop := GetTickCount;
  until (stop - start) >= msec;
end;

constructor TTicker.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fDrawThread := TDrawThread.Create(self);
  [...]
end;
Nun meine zwei Probleme:

1.) Ich habe ja vorher einen Timer mit dem Intervall von einer Millisekunde verwendet. Ich habe hier nun sowohl mit Sleep(1) als auch mit Delay(1) gearbeitet, aber in beiden Fällen liegt die CPU-Auslastung bei 100% (!). Beim Timer lag sie weit unter 10%.

2.) Ich bekomme ständig vom Compiler die Fehlermeldung "Thread Error: Handle ist ungültig(6)", danach funktioniert nichts mehr. Ich kann dann gleich Delphi beenden, da nur noch AVs kommen, wenn ich irgendwas mache (Speichern, erneutes Kompilieren, etc.).

Gruß
Sascha

Bernhard Geyer 26. Apr 2006 08:11

Re: Probleme mit Thread in eigener Komponente
 
Zitat:

Zitat von Sascha L
2.) Ich bekomme ständig vom Compiler die Fehlermeldung "Thread Error: Handle ist ungültig(6)", danach funktioniert nichts mehr. Ich kann dann gleich Delphi beenden, da nur noch AVs kommen, wenn ich irgendwas mache (Speichern, erneutes Kompilieren, etc.).

Zeichnet die DrawEntries-Methode etwas in GUI-Controls? Falls ja hast Du auch den Hinweis gelesen das VCL-Controls nur synchronisiert angesprochen werden dürfen da die VCL-Controls nicht Thread-Save sind?

Sascha L 26. Apr 2006 08:15

Re: Probleme mit Thread in eigener Komponente
 
DrawEntries zeichnet auf sich selber. Also auf dem Canvas vom Ticker, welcher ja von TGraphicControl kommt.

Aber auch wenn ich Synchronize verwende, bleibt der Fehler bestehen.

Ich habe festgestellt, dass das Problem beim Beenden auftritt. Beim Destroy des Tickers führe ich Terminate aus und dann gebe ich das fDrawThread frei. Was merkwürdig ist: Wenn hier ein Fehler liegt und dadurch mein Programm abschmiert, ist das ja noch ok, aber selbst wenn das Programm dann beendet ist, funktioniert Delphi nicht mehr, weil überall diese Handle-Fehlermeldungen kommen und ständig AVs bzgl. der rtl10.bpl (oder so ähnlich).

Grendel 26. Apr 2006 08:28

Re: Probleme mit Thread in eigener Komponente
 
Zitat:

Zitat von Sascha L
Ich habe festgestellt, dass das Problem beim Beenden auftritt. Beim Destroy des Tickers führe ich Terminate aus und dann gebe ich das fDrawThread frei.

Und Du wartest auch sauber auf das Ende des Threads? Zeig am besten mal den Codeabschnitt, der den Thread beendet.

Bis neulich ...

GuenterS 26. Apr 2006 08:41

Re: Probleme mit Thread in eigener Komponente
 
Wenn Du den Thread selbst freigeben möchtest, solltest Du die Eigenschaft von TThread "FreeOnTerminate" auf false setzen.

Robert Marquardt 26. Apr 2006 09:01

Re: Probleme mit Thread in eigener Komponente
 
Zitat:

Zitat von Sascha L
DrawEntries zeichnet auf sich selber. Also auf dem Canvas vom Ticker, welcher ja von TGraphicControl kommt.

Das ist Unsinn. Ticker liegt auf einer Form und wird daher vom Hauptthread gehandhabt. Das Malen vom Thread aus *muss* synchronisiert werden.
Ein Sleep(1) = 1 Millisekunde ist wohl kaum als grosse Verzoegerung zu betrachten. Du malst also mit voller Kraft dauernd die Control neu.
Delay ist noch schlimmer, da es die Zeitscheibe des Threads garnicht freigibt.

jim_raynor 26. Apr 2006 09:35

Re: Probleme mit Thread in eigener Komponente
 
Das Problem ist erstmal, dass der Timer nur auf 50ms oder so genau ist, heisst selbst wenn du den Timer auf 1ms stellst und die Verarbeitung dort weniger als 1ms dauert, wird er niemals 1000mal pro Sekunde anschlagen, von daher erklärt sich auch, warum die CPU Auslastung mit dem Sleep bei 100% liegt, da er dort nun tatsächlich wesentlich öfter die Operationen ausführt. Mit dem Timer macht er es bei weitem nicht so oft.

Sascha L 26. Apr 2006 09:37

Re: Probleme mit Thread in eigener Komponente
 
Das Problem mit den AVs habe ich gelöst. War ein ziemlich dämlicher Fehler von mir :oops:

Das hier geht ja logischerweise nicht:
Delphi-Quellcode:
Thread := Thread.Create(true);
Thread.FreeOnTerminate := true;

Thread.Terminate;
Thread.Free; // <---
@Robert: Wie mach ich das dann am besten, dass er eine Millisekunde wartet und erst dann die Schleife wieder ausführt?

Robert Marquardt 26. Apr 2006 10:20

Re: Probleme mit Thread in eigener Komponente
 
Eine Millisekunde ist viel zu kurz.
Schildere doch erst einmal was du machen willst.

Sascha L 26. Apr 2006 10:31

Re: Probleme mit Thread in eigener Komponente
 
Es wird ein Text horizontal gescrollt. Eben ein Ticker, so wie bei N24, etc. Der soll aber nun flüssig gescrollt werden, also muss die Berechnung sehr häufig aufgerufen werden.

Mit Sleep(10) sieht das ganze schon gut aus und sieht optisch genauso aus, wie beim Timer mit einem Intervall von 1. :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:56 Uhr.
Seite 1 von 2  1 2      

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