Delphi-PRAXiS
Seite 1 von 5  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Thread + Timer, Einbinden von TimerThread.pas (https://www.delphipraxis.net/181814-thread-timer-einbinden-von-timerthread-pas.html)

MarLe 10. Sep 2014 14:10

Delphi-Version: XE2

Thread + Timer, Einbinden von TimerThread.pas
 
Hallo Sir Rufo,

kannst du mir mal kurz die Anwendung deiner Unit TimerThread.pas http://www.delphipraxis.net/1270100-post13.html erläutern (wie muss ich die einbinden).
Ich habe bisher Threads noch nicht verwendet, zwar hier Vieles gelesen, aber auch nicht alles verstanden.
Bin mir auch nicht sicher ob die Unit für mein Prog passend ist. Ich möchte in meinem Prog zyklisch z.B. alle 5 Minuten aus einer Textdatei Werte holen, die dann vorhalten/aufbereiten um diese dann im Prog zu verwenden. Mir geht's jetzt mehr ums Prinzip nicht um den Feinschliff.
Vielen Dank im voraus.

Starten/Stoppen tue ich den Ablauf über das Property .Enabled;
Den zyklisch auszuführenden Code habe ich bei .ExecuteTimed plaziert.
Muss ich da auch noch Terminated abfragen?
Soweit scheint es zu funktionieren, wenn ich stoppe wird aber noch ein Durchlauf gemacht.

Gruß MarLe

Sir Rufo 10. Sep 2014 16:47

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Jupp, dass nach dem
Delphi-Quellcode:
Enabled := False
noch einmal
Delphi-Quellcode:
ExecuteTimed
aufgerufen wird, liegt daran, dass ich vergessen habe im Setter von
Delphi-Quellcode:
Enabled
den Event auszulösen.

Habe ich jetzt mal geändert und zusätzlich dahingehend erweitert, dass der Event nur bei einer echten Änderung auslöst (
Delphi-Quellcode:
Interval
und
Delphi-Quellcode:
Enabled
).

Ein kleiner Fehler war auch noch im
Delphi-Quellcode:
Execute
, da wurde der Wert
Delphi-Quellcode:
LInterval
nicht benutzt :oops:

Zur Verwendung: Am sinnvollsten ist es sich von dieser Klasse eine neue Klasse abzuleiten.
Delphi-Quellcode:
unit MyTimerThread;

interface

uses
  TimerThread;

type
  TMyTimerThread = class( TTimerThread )
  protected
    procedure ExecuteTimed; override;
  end;

implementation

procedure TMyTimerThread.ExecuteTimed;
begin
  // hier jetzt der eigene Code rein
end;

end.
Hier die korrigierte Version der Unit:
Delphi-Quellcode:
unit TimerThread;

interface

uses
  System.Classes,
  System.SyncObjs;

const
  TIMERTHREAD_INTERVAL_DEFAULT = 1000;
  TIMERTHREAD_ENABLED_DEFAULT = True;

type
  TTimerThread = class( TThread )
  private
    FCS : TCriticalSection;
    FEvent : TEvent;
    FInterval : Cardinal;
    FEnabled : Boolean;
    procedure SetInterval( const Value : Cardinal );
    function GetInterval : Cardinal;
    procedure SetEnabled( const Value : Boolean );
    function GetEnabled : Boolean;
  protected
    procedure Execute; override; final;
    procedure ExecuteTimed; virtual;
    // ACHTUNG! Das gibt es erst ab Delphi XE2
    procedure TerminatedSet; override;
  public
    constructor Create;
    destructor Destroy; override;

    property Interval : Cardinal read GetInterval write SetInterval default TIMERTHREAD_INTERVAL_DEFAULT;
    property Enabled : Boolean read GetEnabled write SetEnabled default TIMERTHREAD_ENABLED_DEFAULT;
  end;

implementation

{ TTimerThread }

constructor TTimerThread.Create;
begin
  FCS := TCriticalSection.Create;
  FEvent := TEvent.Create( nil, False, False, '' );
  inherited Create( False );
  FInterval := TIMERTHREAD_INTERVAL_DEFAULT;
  FEnabled := TIMERTHREAD_ENABLED_DEFAULT;
end;

destructor TTimerThread.Destroy;
begin

  inherited;
  FEvent.Free;
  FCS.Free;
end;

procedure TTimerThread.Execute;
var
  LInterval : Cardinal;
begin
  inherited;
  while not Terminated do
    begin
      if Enabled then
        LInterval := Interval
      else
        LInterval := INFINITE;

      if FEvent.WaitFor( LInterval ) = TWaitResult.wrTimeout
      then
        ExecuteTimed;
    end;
end;

procedure TTimerThread.ExecuteTimed;
begin

end;

function TTimerThread.GetEnabled : Boolean;
begin
  FCS.Enter;
  try
    Result := FEnabled;
  finally
    FCS.Leave;
  end;
end;

function TTimerThread.GetInterval : Cardinal;
begin
  FCS.Enter;
  try
    Result := FInterval;
  finally
    FCS.Leave;
  end;
end;

procedure TTimerThread.SetEnabled( const Value : Boolean );
begin
  FCS.Enter;
  try
    if Value <> FEnabled then
    begin
      FEnabled := Value;
      FEvent.SetEvent;
    end;
  finally
    FCS.Leave;
  end;
end;

procedure TTimerThread.SetInterval( const Value : Cardinal );
begin
  FCS.Enter;
  try
    if Value <> FInterval then
    begin
      FInterval := Value;
      FEvent.SetEvent;
    end;
  finally
    FCS.Leave;
  end;
end;

procedure TTimerThread.TerminatedSet;
begin
  inherited;
  FEvent.SetEvent;
end;

end.

MarLe 11. Sep 2014 07:22

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Guten Morgen,

den Fehler im Execute hatte ich beim "Studieren" der Unit auch schon korrigiert.
Die anderen Änderungen habe ich umgesetzt und jetzt schaut's gut aus, Danke für die Unterstützung.

Noch eine Frage zu der Vorbelegung TIMERTHREAD_ENABLED_DEFAULT = True;
Müsste der Ablauf nach einem .Create nicht gleich starten, bei mir startet es erst nach einem zusätzlichen .Enabled := True;

Gruß MarLe

Sir Rufo 11. Sep 2014 08:08

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Jo, stimmet, da fehlte im
Delphi-Quellcode:
Create
doch tatsächlich
Delphi-Quellcode:
FEnabled := TIMERTHREAD_ENABLED_DEFAULT;
:)

Ist jetzt auch drin ;)

MarLe 11. Sep 2014 10:33

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Jetzt habe ich noch zwei Verständnisfragen:

Soll im .Execute nicht auf FEnabled abgefragt werden, oder ist das egal?
Ich habe jetzt mal zum Testen auch den Thread gestoppt, mit .Terminate;
Wie starte ich diesen wieder mit .Start; (was macht .ResetEvent) hat so nicht funktioniert ?

Gruß MarLe

Sir Rufo 11. Sep 2014 10:51

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Im
Delphi-Quellcode:
Execute
wird doch
Delphi-Quellcode:
Enabled
überprüft
Delphi-Quellcode:
      if Enabled then
        LInterval := Interval
      else
        LInterval := INFINITE;
Noch mehr prüfen? Worauf und wozu? ;)

Wenn ein Thread mit
Delphi-Quellcode:
Terminate
beendet wurde, dann ist der durch mit dem Thema und du musst den Thread komplett neu erstellen. Ein Neustart nach
Delphi-Quellcode:
Terminate
ist da nicht vorgesehen.

Wo ist denn da
Delphi-Quellcode:
ResetEvent
in dem Source? :gruebel:

MarLe 11. Sep 2014 11:56

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Ich kann ja auch auf FEnabled (statt Enabled) abfragen, funktioniert auch, deshalb die Frage.
Die zweite Frage hat sich erledigt, da habe ich woanders was von ResetEvents gelesen, aber falsch aufgefasst.

Gruß MarLe

Sir Rufo 11. Sep 2014 12:15

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Zitat:

Zitat von MarLe (Beitrag 1272200)
Ich kann ja auch auf FEnabled (statt Enabled) abfragen, funktioniert auch, deshalb die Frage.

Ja kann man, aber dann so:
Delphi-Quellcode:
  FCS.Enter:
  try
      if FEnabled then
        LInterval := FInterval
      else
        LInterval := INFINITE;
  finally
    FCS.Leave;
  end;
Die Delphi-Referenz durchsuchenTCriticalSection schützt vor dem gleichzeitigen Zugriff von unterschiedlichen Threads. Bei der Abfrage über die Eigenschaft ist das im Getter und Setter schon drin (siehe Source) und darum kann man die Eigenschaften gefahrlos benutzen, ansonsten muss man sich um den Schutz selber kümmern.

Bei Threads gibt es neben dem es funktioniert (kompiliert und ist auch mal gelaufen) auch noch ein es funktioniert gesichert immer ;)

MarLe 11. Sep 2014 12:26

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Ok alles klar, so wie du es beschrieben hast habe ich es auch gemeint, ist quasi egal ob ich auf FEnabled oder Enabled abfrage.
"es funktioniert gesichert immer" ist mir natürlich am liebesten!

Gruß Marle

LTE5 2. Jan 2018 00:38

AW: Thread + Timer, Einbinden von TimerThread.pas
 
Weile ich ein anderes Thema damit nicht belasten möchte hier die Frage.

Ist dieser TimerThread mit Warte-Events nicht anderes als ein normaler TThread mit einer while-Schleife und einem Sleep(1234) im Execute-Teil?
Nur.. mit Events eben.. und nicht mit Sleep?


Wie sähe das hier mit dem TimerThread aus?
Delphi-Quellcode:
procedure TMyNormalThread.Execute;
begin
  while not Terminated do
   begin
    Sleep(1000);

    if 1 = 2 then
     // viel zu tun
   end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:52 Uhr.
Seite 1 von 5  1 23     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