AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Funktionsweise Thread.WaitFor

Funktionsweise Thread.WaitFor

Ein Thema von SyntaxXx · begonnen am 13. Aug 2014 · letzter Beitrag vom 12. Jan 2021
Antwort Antwort
Seite 1 von 2  1 2   
SyntaxXx

Registriert seit: 14. Dez 2008
328 Beiträge
 
Delphi XE4 Architect
 
#1

Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 14:55
Hallo zusammen,
ich habe gerade Probleme mit den Threads.
Ich möchte gerne irgendwie warten, bis ein Thread erfolgreich beendet wurde.
Dafür habe ich nun die Methode "WaitFor" gefunden.
Nur verstehe ich die Funktionsweise nicht.

Hier der Aufbau meiner Anwendung:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    importList: TStringList;
  public
    { Public-Deklarationen }
  end;

  TThread1 = class(TThread)
    protected
      procedure Execute; override;
    private
      IdHTTP1: TIdHTTP;
      page: String;
      response: String;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TThread1.Execute;
begin
  IdHTTP1 := TIdHTTP.Create();
  self.response := IdHTTP1.Get(self.page);
end;

procedure TForm1.Button1Click(Sender: TObject);
var Thread1: TThread1;
begin
    Thread1 := TThread1.Create(True);
    Thread1.FreeOnTerminate := True;
    Thread1.response := 'Foo';
    Thread1.page := 'http://google.de';
    Thread1.Start;

    showmessage(Thread1.response);
end;
end.
Es ist klar, dass ich jetzt nur eine Meldung mit "Foo" bekomme, da der Thread ja noch nicht beendet wurde.
Wie kann ich nun warten, bis der Thread beendet wurde um dann die Meldung auszugeben?
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 15:12
Wie kann ich nun warten, bis der Thread beendet wurde um dann die Meldung auszugeben?
Na eben mit Delphi-Referenz durchsuchenTThread.WaitFor ... allerdings ist es doof, wenn du den Thread automatisch beim Beenden ins Nirwana schickst. Von wem willst du dann noch was holen?

Und wenn du auf den Thread wartest, dann ist deine UI blockiert ... warum dann einen Thread?
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var Thread1: TThread1;
begin
    Thread1 := TThread1.Create(True);
    try
      // Thread1.FreeOnTerminate := True;
      Thread1.response := 'Foo';
      Thread1.page := 'http://google.de';
      Thread1.Start;
      Thread1.WaitFor;
    
      showmessage(Thread1.response);
    finally
      Thread1.Free;
    end;
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
SyntaxXx

Registriert seit: 14. Dez 2008
328 Beiträge
 
Delphi XE4 Architect
 
#3

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 15:23
Ahhhh ok, das war einfach.
Ok, du hast recht, macht natürlich jetzt keinen Sinn, mit nem Thread zu arbeiten.
  Mit Zitat antworten Zitat
Benutzerbild von Nersgatt
Nersgatt

Registriert seit: 12. Sep 2008
Ort: Emlichheim
693 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 15:35
Du kannst natürlich OnTerminate etwas zuweisen. Das Ereignis wird ausgelöst, wenn der Thread fertig ist
Jens
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
5.742 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 16:08
Und das tolle daran: OnTerminate wird sogar schon im Hauptthread ausgeführt.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
38.711 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 16:27
Und das tolle daran: OnTerminate wird sogar schon im Hauptthread ausgeführt.
Und das Allerbeste,

Man kann darin sogar auf Exceptions prüfen. Also die, welche im Thread auftrat und wodurch der Thread abgeschossen wurde.
Denn, im Gegensatz um Hauptthread, werden diese Exception zwar ebenfalls abgefangen, aber nicht dem Benutzer "angezeigt".

Der Grund, warum die RTL/VCL das macht: Windows beendet Prozesse, womit sich das ganze Programm verabschieden würde, wenn in irgendeinem Thread eine Exceptions bis zur Wurzel (ins Windows) durch rauscht.

Delphi-Referenz durchsuchenTThread.FatalException
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (13. Aug 2014 um 16:41 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
5.742 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 16:34
Wieder was gelernt, hätte ich das mal früher gewusst
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#8

AW: Funktionsweise Thread.WaitFor

  Alt 13. Aug 2014, 16:58
Generell sollte man das Thread-Thema etwas anders anfassen:

Man stelle sich das als einen zusätzlichen Mitarbeiter vor, dem man eine Aufgabe gibt und wenn die Aufgabe abgeschlossen ist, dann gibt es wieder eine Rückmeldung.

Und wie im wahren Leben hat dieser Mitarbeiter einen Postkorb, wo alle Arbeiten hineinkommen und diese arbeitet der dann der Reihe nach ab.

Der Thread
Delphi-Quellcode:
unit HttpRequestThread;

interface

uses
  System.Generics.Collections,
  System.SyncObjs,
  System.Classes;

type
  TResponseNotify = procedure( const Request, Response : string ) of object;

  THttpRequestThread = class( TThread )
  private
    FCS : TCriticalSection;
    FEvent : TEvent;
    FQueue : TQueue<string>;
    FOnResponse : TResponseNotify;
    procedure SetOnResponse( const Value : TResponseNotify );
    function GetOnResponse : TResponseNotify;
    function GetQueueItem : string;
    procedure ProcessQueueItem;
    procedure DoResponseNotify( const ARequest, AResponse : string );
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    constructor Create;
    destructor Destroy; override;

    procedure Add( const ARequest : string );

    property OnResponse : TResponseNotify read GetOnResponse write SetOnResponse;
  end;

implementation

uses
  System.SysUtils,
  IdException,
  IdHTTP;

{ THttpRequestThread }

procedure THttpRequestThread.Add( const ARequest : string );
begin
  FCS.Enter;
  try
    FQueue.Enqueue( ARequest );
    FEvent.SetEvent;
  finally
    FCS.Leave;
  end;
end;

constructor THttpRequestThread.Create;
begin
  FCS := TCriticalSection.Create;
  FEvent := TEvent.Create( nil, False, False, '' );
  FQueue := TQueue<string>.Create;
  inherited Create( False );

end;

destructor THttpRequestThread.Destroy;
begin

  inherited;
  FreeAndNil( FQueue );
  FreeAndNil( FEvent );
  FreeAndNil( FCS );
end;

procedure THttpRequestThread.DoResponseNotify( const ARequest, AResponse : string );
begin
  if MainThreadID = CurrentThread.ThreadID
  then
    begin
      if Assigned( OnResponse )
      then
        OnResponse( ARequest, AResponse );
    end
  else
    Queue(
        procedure
      begin
        DoResponseNotify( ARequest, AResponse );
      end );
end;

procedure THttpRequestThread.Execute;
begin
  inherited;
  while not Terminated do
    begin
      FEvent.WaitFor;
      if not Terminated
      then
        ProcessQueueItem;
    end;
end;

function THttpRequestThread.GetOnResponse : TResponseNotify;
begin
  FCS.Enter;
  try
    Result := FOnResponse;
  finally
    FCS.Leave;
  end;
end;

function THttpRequestThread.GetQueueItem : string;
begin
  FCS.Enter;
  try
    Result := FQueue.Dequeue;
    if FQueue.Count > 0
    then
      FEvent.SetEvent;
  finally
    FCS.Leave;
  end;
end;

procedure THttpRequestThread.ProcessQueueItem;
var
  LRequest : string;
  LResponse : string;
  LHttp : TIdHTTP;
begin
  LHttp := TIdHTTP.Create( nil );
  LHttp.HandleRedirects := True;
  try
    LRequest := GetQueueItem;
    try
      LResponse := LHttp.Get( LRequest );
    except
      on E : EIdException do
        begin
          LResponse := E.ClassName + ': ' + E.Message;
        end;
    end;
    DoResponseNotify( LRequest, LResponse );
  finally
    LHttp.Free;
  end;
end;

procedure THttpRequestThread.SetOnResponse( const Value : TResponseNotify );
begin
  FCS.Enter;
  try
    FOnResponse := Value;
  finally
    FCS.Leave;
  end;
end;

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

end.
und ein kleine Anwendung
Delphi-Quellcode:
unit FormMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  HttpRequestThread;

type
  TForm1 = class( TForm )
    Button1 : TButton;
    ListBox1 : TListBox;
    procedure Button1Click( Sender : TObject );
  private
    FHttpRequest : THttpRequestThread;
    procedure HttpRequestResponse( const Request, Response : string );
    procedure LogMsg( const AMsgStr : string );
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

procedure TForm1.AfterConstruction;
begin
  inherited;
  FHttpRequest := THttpRequestThread.Create;
  FHttpRequest.OnResponse := HttpRequestResponse;
end;

procedure TForm1.BeforeDestruction;
begin
  inherited;
  FreeAndNil( FHttpRequest );
end;

procedure TForm1.Button1Click( Sender : TObject );
var
  LUrl : string;
  LIdx : Integer;
begin
  LUrl := 'http://google.de';
  for LIdx := 1 to 10 do
    begin
      LogMsg( 'Request ' + LUrl );
      FHttpRequest.Add( LUrl );
    end;
end;

procedure TForm1.HttpRequestResponse( const Request, Response : string );
begin
  LogMsg( Request + ' => ' + Response );
end;

procedure TForm1.LogMsg( const AMsgStr : string );
begin
  ListBox1.Items.Add( DateTimeToStr( Now ) + ': ' + AMsgStr );
end;

end.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49565
299 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: Funktionsweise Thread.WaitFor

  Alt 11. Jan 2021, 14:15
Ich hole diesen etwas betagten Thread noch mal hoch, weil:
Prinzipiell selbes Prob, nur hab ich ges. 5 Threads, auf dessen Erledigung ich warte und die weitere Prorammausführung davon abhängt, wer wann fertig ist.

Ablauf in etwa so:
- Zum Prog-Begin starten 3 Threads um Daten zu lesen & zu evaluieren.
(Kann im worst-case bis zu 10 Sekunden dauern !)
- Proggie soll derweil weiter initialisieren, die GUI aufbauen, den User grüßen, usw.

Warte-Punkt 1)
Thread-1 kann, muss aber noch nicht bis dahin fertig sein - d.h. auf den MUSS gewartet werden, weil alles weitere von dessen Daten abhängt.
Wenn fertig, erfolgen ab hier weiter GUI-Init's und 2 weitere Threads starten

Warte-Punkt 2)
Wie unter 1, Thread-2 fertig ? Wobei hier datenabhgig eine Meldgugng angzeigt und entspechend reagiert werden muss.

Warte Punkt-3)
Das warten auf Thread-3 ist nicht zwingend zeitrelevant (und dauert i.d.R. ach am längsten),
es wäre jedoch "nice to have" umgehend nach dessen Ende eine weitere Meldng zu zeigen und das Display mit neuen Daten upzudaten.


Meine Idee:
Wenn hier jeder Thread seinen eigenen Event nach Ablauf feuert, wie kann ich da in der Main-Form darauf reagieren ? (Hier spez. Thread 1 + 2 in einer Loop)
Get das evtl. mit "WaitForSingleObject" ?

Für Thread-3 könnte ich auch gut mit einer CallBack-procedure leben.

Wichtig ist allgemein, dass das Proggie nicht bei Fehlern oder langen Lesezeiten hängt und weiter bedienbar ist.
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.629 Beiträge
 
Delphi 10.3 Rio
 
#10

AW: Funktionsweise Thread.WaitFor

  Alt 11. Jan 2021, 21:20
Thread 1 2 und 3 kannst du Vermutlich über IFuture abbilden.
Du startest die Futures und
machst deinen GUI-Aufbau...bis irgendwo in dem Verlauf die Werte der Futures ausgelesen werden und der GUI-Aufbau wartet dann solange bist die Werte bereittehen. Das warten passiert da wo die Werte der Furures gelesen werden.

Für endliche Arbeitslasten nutze ich die Klassen aus AnonThread.pas
https://blogs.embarcadero.com/cross-...-notification/
Ich brauche diese Klassen um die Oberflächen von Windows und Mobilen Anwendungen Responsive zu halten. Es ist recht komfortabel die Logick die im thread ausgeführt wird in das OnClick Ereignis des Buttons zu inlinen und auch die Erfolgs- oder Misserfolgsmeldung zu inlinen.
Andreas
#PerfMatters

Geändert von QuickAndDirty (11. Jan 2021 um 21:34 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

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 16:48 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf