AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Thread soll eine Minute warten: Sleep oder Timer?

Thread soll eine Minute warten: Sleep oder Timer?

Ein Thema von Bbommel · begonnen am 2. Feb 2009 · letzter Beitrag vom 13. Mär 2021
Antwort Antwort
Seite 1 von 3  1 23   
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
648 Beiträge
 
Delphi 12 Athens
 
#1

Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 11:38
Hallo zusammen,

nachdem ich mich jahrelang um Threads herumdrücken konnte (außer vor ein paar Jahren in der Uni in der Theorie), komme ich nun an dem Thema wohl nicht mehr vorbei, da ich in einem Projekt eine periodische Datenbank-Abfrage implementieren möchte, die den Benutzer aber nicht weiter stören soll. Konkret soll also einmal pro Minute eine MSSQL-Datenbank abgefragt werden und nur, falls dort bestimmte Informationen vorliegen, soll der Benutzer bei seiner eigentlichen Arbeit gestört werden.

Ich habe nun noch ein Konstruktions- bzw. Verständnisproblem. Wie schaffe ich es am elegantesten, dass der Thread einerseits eine Minute lang nix macht, nachdem die Datenbank abgefragt wurde, andererseits aber dennoch ziemlich schnell terminiert wird, sobald der Hauptthread das wünscht (weil das Programm beendet wird oder aus anderen Gründen). Denn: Wenn man den Thread mit "sleep" Schlafen schickt, bekommt er von einem Terminate ja erst mal nix mehr mit.

Ich hab hier in der DP schon ein bisschen geschmökert, was mir auch die eine oder andere Idee gebracht hat, aber so richtig sicher bin ich mir noch nicht, was nun die "ultimative" Lösung ist (obwohl ich jetzt eher erwartet hätte, dass das ein Standard-Problem wäre - nicht richtig gesucht?) Wobei ich jetzt beim Tippen das Gefühl bekommen habe, auf einem guten Weg zu sein...

Ich hab mir mal ein kleines Beispiel gebastelt, das mit Datenbanken noch gar nix macht (ist ja auch nicht mein eigentliches Problem... hoffentlich) und mit dem sich die Überlegungen ganz gut zeigen lassen:

Die Thread-Klasse:

Delphi-Quellcode:
unit thread;

interface

uses
  Classes, SyncObjs;

type
  TCalcThread = class(TThread)
  private
    { Private-Deklarationen }
    resultText: string;
  protected
    procedure Execute; override;
    procedure ShowResult;
  public
    calcValue: integer;
    constructor Create(CreateSuspended: Boolean);
  end;

var CriticalParams : TCriticalSection;

implementation

uses main, sysUtils;

{ Wichtig: Methoden und Eigenschaften von Objekten in visuellen Komponenten dürfen
  nur in einer Methode namens Synchronize aufgerufen werden, z.B.

      Synchronize(UpdateCaption);

  und UpdateCaption könnte folgendermaßen aussehen:

    procedure TCalcThread.UpdateCaption;
    begin
      Form1.Caption := 'Aktualisiert in einem Thread';
    end; }


{ TCalcThread }

procedure TCalcThread.ShowResult;
begin
  thread1_main.LabelResult.Caption:=resultText;
end;

procedure TCalcThread.Execute;
var myValue: integer;
begin
  { Thread-Code hier einfügen }
  while not terminated do begin
    CriticalParams.Acquire;
    myValue:=calcValue;
    CriticalParams.Release;

    if myValue=-1 then
      resultText:='nix gesetzt.'
    else
      resultText:=intToStr(myValue*80);
    Synchronize(ShowResult);
    sleep(10000);
  end;
end;

constructor TCalcThread.Create(CreateSuspended: Boolean);
begin
  inherited;

  calcValue:=-1;
end;

end.
(damit ich beim Testen nicht ewig warten muss, legt sich der Thread hier nur 10 Sekunden Schlafen)

Im Hauptprogramm gibt es nun einen Button, mit dem man den Thread beenden kann:

Delphi-Quellcode:
procedure Tthread1_main.ButtonStopThreadClick(Sender: TObject);
begin
  theThread.Terminate;

  // warten bis der Thread beendet wurde...
  theThread.WaitFor;
  messageDlg('Der Thread ist durch.',mtInformation,[mbOk],0);
  theThread.Free;
  theThread:=nil;
end;
Das Problem sollte klar sein: Es kann bis zu 10 Sekunden dauern, bis der Thread nach dem Klick auf den Button wirklich beendet wird. Am einfachsten wäre es ja, wenn man das sleep irgendwie von außen unterbrechen könnte - also das Hauptprogramm schickt einen Weckruf, der den Wecker einfach etwas vorstellt, aber sowas habe ich nicht gefunden. Also wird man wohl drumrum basteln müssen...

Am einfachsten wäre es wahrscheinlich, wenn man nicht 10 Sekunden wartet, sondern 10 mal eine Sekunde, so dass aus
    sleep(10000); ein
Delphi-Quellcode:
i:=0
while (not terminated) and (i<10) do begin
  sleep(1000);
  inc(i);
end;
würde. Der Hauptthread bekäme dann wohl viel schneller eine Rückmeldung, aber irgendwie fühlen sich diese ständigen Wechsel in den Thread nicht so richtig gut an. Hat irgendwie was vom aktiven Warten.

Als andere Alternative wollte ich jetzt eigentlich vorschlagen, dass ein Timer den Thread periodisch freigibt und neu erzeugt, aber beim Schreiben kam mir jetzt gerade der Gedanke, dass ein Timer wahrscheinlich ein guter Ansatz ist, aber ein Suspend/Resume wahrscheinlich besser, als das Dingen zu zerstören und neu anzulegen.

Das heißt, die Execute-Methode vom Thread sähe dann so aus:

Delphi-Quellcode:
procedure TCalcThread.Execute;
var myValue: integer;
begin
  { Thread-Code hier einfügen }
  while not terminated do begin
    CriticalParams.Acquire;
    myValue:=calcValue;
    CriticalParams.Release;

    if myValue=-1 then
      resultText:='nix gesetzt.'
    else
      resultText:=intToStr(myValue*80);
    Synchronize(ShowResult);
    Suspend;
  end;
end;
Und im Hauptthread gibt es dann ein Timer-Ereignis und eine Änderung beim Klicken auf den Button:

Delphi-Quellcode:
procedure Tthread1_main.TimerThreadTimer(Sender: TObject);
begin
  theThread.Resume;
end;

procedure Tthread1_main.ButtonStopThreadClick(Sender: TObject);
begin
  TimerThread.Enabled:=false;
  theThread.Terminate;
  theThread.Resume; // damit das Dingen auch merkt, dass er beendet wurde...

  // warten bis der Thread beendet wurde...
  theThread.WaitFor;
  messageDlg('Der Thread ist durch.',mtInformation,[mbOk],0);
  theThread.Free;
  theThread:=nil;
end;
Ist da irgendein Denkfehler drin oder ist das die "ultimative Lösung", nach der ich gesucht habe? Mir kommt sie gerade eigentlich ganz gut vor.

Ich bin auf eure Rückmeldungen gespannt.

Danke und bis denn
Bbommel
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 11:46
In einem Thread ist sleep nutzbar (nur auf Terminate sollte man achten). Besser ist waitforsingleobject mit einer Zeitangabe.

Edit:
Waitforsingleobject irgendwie so:
Delphi-Quellcode:
constructor Tmythread.Create(CreateSuspended: Boolean);
begin
  inherited Create(false);
  FEvent:=TEvent.Create(nil,true,false,'');
end;

destructor Tmythread.Destroy;
begin
  FEvent.Free;
  inherited;
end;

procedure Tmythread.DoSomething;
begin
  //abstract ;-)
end;

procedure Tmythread.Terminate;
begin
  inherited;
  FEvent.SetEvent;
end;

procedure Tmythread.execute;
begin
  while not terminated do
  begin
    DoSomething;
    FEvent.ResetEvent;
    FEvent.WaitFor(10000);
  end;
end;
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
nuclearping

Registriert seit: 7. Jun 2008
708 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 11:46
Denke mal, dass das auch mit GetTickCount gehen sollte. AFAIK ist das Threadsafe.
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#4

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 11:54
Hallo,

wie wärs denn mit KISS (keep it simple and stupid):

Das Programm wartet nur darauf, beendet zu werden.

Die Funktionalität wird im Timer Service erledigt, falls was vorliegt.

Weder Thread noch sleep nötig.

Gruss Reinhard
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.097 Beiträge
 
Delphi 12 Athens
 
#5

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 11:54
ich würde vielleicht nich direkt ein 60-Sekunden-Sleep einbauen, denn so kannst du den Thread nicht mehr so schön/schnell beenden. (vorallem wenn das Programm beendet werden soll ... wär ja blöd, wenn du dann im schlimmsten Fall noch 'ne Minute gewartet werden müßte)

CPU-schonend und unterbrechbar wäre z.B. sowas:
Delphi-Quellcode:
Var T: LongWord;
  ThreadSollBeendetWerden: Boolean;
...

T := GetTickCount;
While (GetTockCount - T < 60000) and not ThreadSollBeendetWerden do
  Sleep(200);
oder was mit WaitFor... wie sirius grad nachtrug
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
648 Beiträge
 
Delphi 12 Athens
 
#6

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 12:03
Zitat von sirius:
In einem Thread ist sleep nutzbar (nur auf Terminate sollte man achten). Besser ist waitforsingleobject mit einer Zeitangabe.
Also sollte ich innerhalb des Threads das
sleep(10000) durch ein
waitForSingleObject(Handle,10000); ersetzen?

So ganz schlau werde ich daraus noch nicht - jetzt bei diesem Versuch wartet der Thread ja, bis er selbst signalisiert (also beendet, wenn ich das richtig verstanden habe) wird. Aber das bringt mich offenbar nicht so richtig weiter oder kann man dieses Signal auch manuell senden? Oder muss ich da einen extra Handler für erstellen?

Ich hatte zu dem Thema auch schon im Thread-Tutorial von Luckie was gelesen, aber dort werden die wait-Funktionen ja gerade auch außerhalb des Threads eingesetzt, was ja auf mein Problem nicht so recht zutrifft.

Bis denn
Bommel
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#7

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 12:09
Ähm, das zuerst gedachte Edit oben sollte hier als Antwort hin.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
648 Beiträge
 
Delphi 12 Athens
 
#8

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 12:11
Zitat von himitsu:
ich würde vielleicht nich direkt ein 60-Sekunden-Sleep einbauen, denn so kannst du den Thread nicht mehr so schön/schnell beenden.
Jepp, genau das ist ja mein Problem.

Zitat von himitsu:
CPU-schonend und unterbrechbar wäre z.B. sowas:
[...]
Nur zum Verständnis noch mal nachgefragt: Das ist ja eigentlich der gleiche Ansatz, wie ich ihn mit dem mehrfachen Hochzählen von i und dazwischen einem kürzeren sleep hatte, nur über den TickCount eleganter, weil die 60 Sekunden besser eingehalten werden können, richtig?

Mein Problem mit dem Ansatz ist nur, dass es sich komisch "anfühlt", wenn andauernd ein Kontextwechsel gemacht wird, obwohl eigentlich gar nichts zu tun ist. Ich kann nur überhaupt nicht einschätzen, ob sowas auch tatsächlich nach bemerkbar ist oder ob ich mir dann den Kopf über ein eher akademisches Problem zerbreche.

Bis denn
Bommel
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
648 Beiträge
 
Delphi 12 Athens
 
#9

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 12:13
Zitat von sirius:
Ähm, das zuerst gedachte Edit oben sollte hier als Antwort hin.
Okay, ich denke es mir einfach hier hin als Antwort auf meine Rückfrage. Sieht gut aus, Danke dir.

Bis denn
Bommel
  Mit Zitat antworten Zitat
Zoot

Registriert seit: 30. Jan 2006
Ort: Hessen
110 Beiträge
 
Delphi 11 Alexandria
 
#10

Re: Thread soll eine Minute warten: Sleep oder Timer?

  Alt 2. Feb 2009, 12:13
Zitat von Reinhard Kern:
Hallo,

wie wärs denn mit KISS (keep it simple and stupid):

Das Programm wartet nur darauf, beendet zu werden.

Die Funktionalität wird im Timer Service erledigt, falls was vorliegt.

Weder Thread noch sleep nötig.

Gruss Reinhard
Verstehe auch nicht, wozu man einen Thread braucht, wenn der eh normalerweise nix tut.
Ein simpler timer reicht doch dann völlig.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:12 Uhr.
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