AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Warten auf Thread Ende

Ein Thema von 4lb3rtO · begonnen am 12. Mär 2013 · letzter Beitrag vom 14. Mär 2013
Antwort Antwort
4lb3rtO

Registriert seit: 11. Okt 2011
11 Beiträge
 
Delphi 2010 Professional
 
#1

Warten auf Thread Ende

  Alt 12. Mär 2013, 15:07
Hallo Leute

Ich hätte mal eine Frage zum Thread-Design und dem Warten auf das Ende eines Threads. Mit Threads in Delphi stehe ich mehr oder weniger immer auf Kriegsfuß
Um während einer Wartezeit (z.B. auf einen Download) eine Animation sehen zu können, lasse ich mir in einem Image eine Gif-Animation anzeigen. Der Download selbst wird in einem Thread ausgeführt.


Die Animation wird mit folgendem Code angezeigt...
{Unit1}
Delphi-Quellcode:
  private
    FBusyAnimation : Boolean;
    procedure SetBusyAnimation(Value: Boolean);
  public
    property BusyAnimation: Boolean read FBusyAnimation write SetBusyAnimation;
  end;
Delphi-Quellcode:
procedure TXMFS.FormCreate(Sender: TObject);
begin
  (Image2.Picture.Graphic as TGIFImage).Animate := True;
  (Image2.Picture.Graphic as TGIFImage).AnimationSpeed := 210;
end;
Delphi-Quellcode:
procedure TXMFS.SetBusyAnimation(Value: Boolean);
begin
  FBusyAnimation := Value;
  if FBusyAnimation then
    Image2.Visible := True
  else
    Image2.Visible := False;
end;

Den Thread erzeuge ich bspw. so...
{Unit1}
Delphi-Quellcode:
  SetBusyAnimation(True);
  TGMD := TThreadGetMBData.Create('artist', 'artist', XMFS.Edit1.Text, '5', True);
  TGMD.FreeOnTerminate := True;
  TGMD.Start;

Thread...
{Unit2}
Delphi-Quellcode:
  TThreadGetMBData = class(TThread)
  private
    FTyp: String;
    FQuery: String;
    FInput: String;
    FLimit: String;
    FShow: Boolean;
    procedure NotifyEndOfThread;
    procedure GetMBData(Typ, Query, Input, Limit: String);
  protected
    procedure Execute; override;
  public
    constructor Create(const ATyp, AQuery, AInput, ALimit: String; AShow: Boolean);
  end;
Delphi-Quellcode:
constructor TThreadGetMBData.Create(const ATyp, AQuery, AInput, ALimit: String; AShow: Boolean);
begin
  inherited Create(True);
  FTyp := ATyp;
  FQuery := AQuery;
  FInput := AInput;
  FLimit := ALimit;
  FShow := AShow;
end;
GetMbData lädt dann die entsprechende Datei herunter
Delphi-Quellcode:
procedure TThreadGetMBData.Execute;
begin
  CoInitialize(nil);
  try
    GetMBData(FTyp, FQuery, FInput, FLimit);
  finally
    Synchronize(NotifyEndOfThread);
  end;
end;

Hier wird nach Thread-Ende die Animation versteckt und xml-Daten ausgelesen
Delphi-Quellcode:
procedure TThreadGetMBData.NotifyEndOfThread;
begin
  XMFS.BusyAnimation := False;
  if FTyp = 'artistthen
    Mb.ReadArtistData(FShow);
  if FTyp = 'release-groupthen
    Mb.ReadReleaseGroupData(FShow);
end;


Ist der Thread und dessen Aufruf so in Ordnung?
Ab und zu kann es nun allerdings vorkommen, das ich nach dem Erzeugen des Threads auf seine Fertigstellung warten muss. Ach wenn ich den Sinn und Zweck eines Threads damit wieder zunichte mache. Letztenendes geht es eigentlich nur um die Animation. Hierzu hatte ich nach dem Create ein "FreeOnTerminate := False" und "WaitFor" verwendet, was jedoch nicht wie gewünscht funktionierte. Muss ich stattdessen WaitForSingleObject verwenden? Oder ein Flag bzw. ein Event?

Bin für jeden Hinweis dankbar, da dies quasi meine ersten Gehversuche mit Threads sind.

Schöne Grüße
4lb3rtO

Geändert von 4lb3rtO (12. Mär 2013 um 15:10 Uhr)
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#2

AW: Warten auf Thread Ende

  Alt 12. Mär 2013, 15:53
Hier wird nach Thread-Ende die Animation versteckt und xml-Daten ausgelesen
Delphi-Quellcode:
procedure TThreadGetMBData.NotifyEndOfThread;
begin
  XMFS.BusyAnimation := False;
  if FTyp = 'artistthen
    Mb.ReadArtistData(FShow);
  if FTyp = 'release-groupthen
    Mb.ReadReleaseGroupData(FShow);
end;
Das kann ohne Synchronize auch über das OnTerminate Event des Threads gelöst werden.

Zitat:
Die dem Ereignis OnTerminate zugeordnete Methode wird im Kontext des Haupt-Threads ausgeführt und nicht im Kontext des Threads, der beendet wird. Das bedeutet, dass Sie sicher auf die Benutzeroberfläche Ihrer Anwendung zugreifen können, ohne die Methode Synchronize aufrufen zu müssen.
Michael Justin
  Mit Zitat antworten Zitat
4lb3rtO

Registriert seit: 11. Okt 2011
11 Beiträge
 
Delphi 2010 Professional
 
#3

AW: Warten auf Thread Ende

  Alt 12. Mär 2013, 16:49
Zitat:
Das kann ohne Synchronize auch über das OnTerminate Event des Threads gelöst werden.

Stimmt. Das ist ja noch wesentlich geschickter. Hier muss man ja keine Progressbar o.ä. mit dem Hauptthread synchronisieren. Danke für den Tip
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#4

AW: Warten auf Thread Ende

  Alt 13. Mär 2013, 18:54
Delphi-Quellcode:
procedure TXMFS.SetBusyAnimation(Value: Boolean);
begin
  FBusyAnimation := Value;
  Image2.Visible := Value;
end;
Wäre das nicht einfacher oder übersehe ich jetzt was?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
4lb3rtO

Registriert seit: 11. Okt 2011
11 Beiträge
 
Delphi 2010 Professional
 
#5

AW: Warten auf Thread Ende

  Alt 14. Mär 2013, 16:02
Vielen Dank für die zahlreichen Hinweise und Tipps Ich habe nun einmal die angesprochenen Änderungen eingefügt. Die read-property und die Variable habe ich entfernt, da sie im späteren Verlauf auch nicht benötigt wird.
Leider funktioniert hier bei der DP kein Line-Highlighting (gelöschte Zeilen rot, neue Zeilen grün markieren/hinterlegen) um die Änderungen besser sichtbar zu machen
Hier einmal der aktuelle Quelltext.

Die Animation wird mit folgendem Code angezeigt...
{Unit1}
Delphi-Quellcode:
  private
    procedure SetBusyAnimation(Value: Boolean);
  public
    property BusyAnimation: Boolean write SetBusyAnimation;
  end;
Delphi-Quellcode:
procedure TXMFS.FormCreate(Sender: TObject);
begin
  (Image2.Picture.Graphic as TGIFImage).Animate := True;
  (Image2.Picture.Graphic as TGIFImage).AnimationSpeed := 210;
end;
Delphi-Quellcode:
procedure TXMFS.SetBusyAnimation(Value: Boolean);
begin
  Image2.Visible := Value;
end;

Den Thread erzeuge ich bspw. so...
{Unit1}
Delphi-Quellcode:
  TGMD := TThreadGetMBData.Create('artist', 'artist', XMFS.Edit1.Text, '5', True);
  TGMD.FreeOnTerminate := True;
  TGMD.Start;

Thread...
{Unit2}
Delphi-Quellcode:
  TThreadGetMBData = class(TThread)
  private
    FTyp: String;
    FQuery: String;
    FInput: String;
    FLimit: String;
    FShow: Boolean;
    procedure NotifyEndOfThread(Sender: TObject);
    procedure GetMBData(Typ, Query, Input, Limit: String);
  protected
    procedure Execute; override;
  public
    constructor Create(const ATyp, AQuery, AInput, ALimit: String; AShow: Boolean);
  end;
Delphi-Quellcode:
constructor TThreadGetMBData.Create(const ATyp, AQuery, AInput, ALimit: String; AShow: Boolean);
begin
  inherited Create(True);
  XMFS.BusyAnimation := True;
  FTyp := ATyp;
  FQuery := AQuery;
  FInput := AInput;
  FLimit := ALimit;
  FShow := AShow;
end;
GetMbData lädt dann die entsprechende Datei herunter
Delphi-Quellcode:
procedure TThreadGetMBData.Execute;
begin
  CoInitialize(nil);
  GetMBData(FTyp, FQuery, FInput, FLimit);
  OnTerminate := NotifyEndOfThread;
end;
Hier wird nach Thread-Ende die xml-Daten ausgelesen und die Animation versteckt
Delphi-Quellcode:
procedure TThreadGetMBData.NotifyEndOfThread(Sender: TObject);
begin
  if FTyp = 'artistthen
    Mb.ReadArtistData(FShow);
  if FTyp = 'release-groupthen
    Mb.ReadReleaseGroupData(FShow);

  XMFS.BusyAnimation := False;
end;


Jetzt müsste ich nur noch bei Bedarf auf die Fertigstellung des Threads warten können, dann wäre es perfekt. Ich glaube ich habe auch mich im ersten Post in der Beziehung etwas missverständlich ausgedrückt. Im Hauptthread müsste ich nach der Erzeugung des Nebenthreads die Möglichkeit haben, auf dessen Fertigstellung zu warten.
Vielleicht auch den Status des Threads abfragen, ob ein Fehler aufgetreten ist?!

Wenn man nun bspw. den Thread wie folgt erzeugt, funktioniert die Animation aufgrund des "WaitFor" und des "Free" nicht mehr
Delphi-Quellcode:
  TGMD := TThreadGetMBData.Create('artist', 'artist', XMFS.Edit1.Text, '5', True);
  TGMD.FreeOnTerminate := False;
  TGMD.Start;

  TGMD.WaitFor;

  // Mach noch etwas

  TGMD.Free;

Was für Möglichkeiten hätte man alternativ um dort eine Pause einzulegen, ohne den Hauptthread einzufrieren und die Animation anzuzeigen?
Änderungsvorschläge und Kritik sind nach wie vor erwünscht Das blöde an der Geschichte ist, das es mehrere solcher Threads gibt und sich das durch das gesamte Programm zieht...
Vielen Dank bis dato
  Mit Zitat antworten Zitat
Antwort Antwort


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 08:00 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