AGB  ·  Datenschutz  ·  Impressum  







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

mehrere Threads sauber beenden

Ein Thema von haentschman · begonnen am 10. Jan 2011 · letzter Beitrag vom 9. Dez 2013
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.300 Beiträge
 
Delphi 12 Athens
 
#11

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 11:36
Die Threads stehen sowieso und tun nix... Die Klasse1 ist nicht der Thread. Klasse1 erzeugt die Threads. Im Destroy der Klasse1 sollen die Threads aufgeräumt werden. Das Sleep(200) sollte imho dazu da sein, daß´die Threads Zeit haben zu reagieren. Aber die bewegen sich ja nicht.
Laut Status der Threads in der Objektliste: Suspended = False sollten sie das aber nicht.

die ThreadUnit Komplett(entspricht Klasse2 des Übersichtsbeispieles):
Delphi-Quellcode:
unit XWebLoader;

interface

uses Classes, SysUtils, SyncObjs, IdHTTP, IdComponent, XWebDataTypes;

type

  TOnFinishLoadEvent = procedure(Sender: TObject; LoaderMessage: TXWebLoaderMessage) of object;
  TOnErrorLoadEvent = procedure(Sender: TObject; LoaderMessage: TXWebLoaderMessage) of object;
  TOnRemoveEvent = procedure(Sender: TObject) of object;

  TXWebLoader = class(TThread)
  strict private
   FCS: TCriticalSection;
   FHTTP: TIdHTTP;
   FXWebLink: string;
   FParameter: string;
   FCookie: string;
   FDeviceName: string;
   FMessageID: Integer;
   FDigit: Integer;
   FGoLoading: Boolean;
   FOnFinish: TOnFinishLoadEvent;
   FOnError: TOnErrorLoadEvent;
   FOnRemove: TOnRemoveEvent;
   FMsg: TXWebLoaderMessage;
   procedure SyncOnFinish;
   procedure SyncOnError;
   procedure CheckAbort(Sender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
  protected
    procedure Execute; override;
    procedure Remove(Sender: TObject);
  public
    constructor Create(Suspended: Boolean);
    destructor Destroy; override;
    procedure GetData(const XWebLink,Parameter,Cookie,DeviceName :string; MessageID,Digit: Integer);
    property OnFinish: TOnFinishLoadEvent read FOnFinish write FOnFinish;
    property OnError: TOnErrorLoadEvent read FOnError write FOnError;
    property OnRemove: TOnRemoveEvent read FOnRemove write FOnRemove;
  end;



implementation

{ TXWebLoader }

procedure TXWebLoader.CheckAbort(Sender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64); // auch ein Versuch den Socket Error der Indys beim Programm Beenden zu kompensieren
begin // war ein Tipp in einem Beitrag. Hier kommt das Programm gar nicht an. Die Threads werden
  if Terminated then // einfach abgewürgt
    FHTTP.Disconnect;
end;

constructor TXWebLoader.Create(Suspended: Boolean);
begin
  inherited Create(Suspended);
  FCS:= TCriticalSection.Create;
  FHTTP:= TIdHTTP.Create;
  FHTTP.OnWork:= CheckAbort;
  FMsg:= TXWebLoaderMessage.Create;
  Self.OnTerminate:= Remove;
end;

destructor TXWebLoader.Destroy;
begin
  FHTTP.Free;
  FMsg.Free;
  FreeAndNil(FCS);
  inherited;
end;

procedure TXWebLoader.Execute;
var
  XWebParameter: TStringStream;
  ResponseStream: TStringStream;
  sl: TStringList;
begin
  inherited;
  if not Terminated then
  begin
    sl:= TStringList.Create;
    try
      XWebParameter:= TStringStream.Create(FParameter);
      try
        ResponseStream:= TStringStream.Create;
        try
          try
            FHTTP.Request.CustomHeaders.Add(FCookie);
            if FParameter = 'then
              FHTTP.Get(FXWebLink,ResponseStream)
            else
              FHTTP.Post(FXWebLink,XWebParameter,ResponseStream);
            ResponseStream.Position:= 0;
            sl.LoadFromStream(ResponseStream,TEncoding.UTF8);
            FMsg.Data:= sl.Text;
            Synchronize(SyncOnFinish);
          except
            on e: Exception do
              begin // evt. noch weitere Informationen in Stringlist oder Klasse dafür ?
                FMsg.Data:= e.Message;
                Synchronize(SyncOnError);
              end;
          end;
        finally
          ResponseStream.Free;
        end;
      finally
        XWebParameter.Free;
      end;
    finally
      sl.Free;
    end;
    Sleep(100); // extra eingefügt
  end;
end;

procedure TXWebLoader.GetData(const XWebLink, Parameter, Cookie, DeviceName :string; MessageID,Digit: Integer);
begin
  FCS.Enter;
  try
    FXWebLink:= XWebLink;
    FParameter:= Parameter;
    FCookie:= Cookie;
    FDeviceName:= DeviceName;
    FMessageID:= MessageID;
    FDigit:= Digit;
    FMsg.ID:= FMessageID;
    FMsg.DeviceName:= FDeviceName;
    FMsg.Digit:= FDigit;
    Self.Start;
  finally
    FCS.Leave;
  end;
end;

procedure TXWebLoader.SyncOnError;
begin
  FCS.Enter;
  try
    if Assigned(FOnError) then
      FOnError(Self,FMsg);
  finally
    FCS.Leave;
  end;
end;

procedure TXWebLoader.SyncOnFinish;
begin
  FCS.Enter;
  try
    if Assigned(FOnFinish) then
      FOnFinish(Self,FMsg);
  finally
    FCS.Leave;
  end;
end;

procedure TXWebLoader.Remove(Sender: TObject);
begin
  FCS.Enter;
  try
    if Assigned(FOnRemove) then
      FOnRemove(Self);
  finally
    FCS.Leave;
  end;
end;

end.

Geändert von haentschman (10. Jan 2011 um 11:40 Uhr)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#12

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 11:40
Zitat:
Das Sleep(200) sollte imho dazu da sein
Und du bist sicher das ein Sleep(200) auf allen Systemen unterschiedlicher Rechengeschwindigkeit immer das gleiche Ergebnis liefert?
Ich habe da andere Erfahrungen gesammelt.
Solange nicht alle Processe korrekt beendet wurden wirst du immer in einer Endlosschleife enden.

gruss
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.757 Beiträge
 
Delphi 10.4 Sydney
 
#13

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 11:52
.. mal ein Schuss ins Blaue.
Wie verhält sich das ganze denn, wenn Du die synchronize Aufrufe
mal auskommentierst.

Die Form soll geschlossen werden - dann kommt noch ein synch Aufruf um etwas anzuzeigen??

Nachtrag:
Was bezweckst Du mit dem inherited Aufruf zu Beginn der execute Methode?

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.300 Beiträge
 
Delphi 12 Athens
 
#14

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 12:10
Zitat:
Was bezweckst Du mit dem inherited Aufruf zu Beginn der execute Methode?
...wenn ich die Tutorials und diversen Beiträge richtig verstanden habe sollte das immer sein. Wenn ich da was falsch verstanden habe, korrigier mich bitte.

Neuigkeiten:

- vieleicht sind wir alle auf dem Holzweg und es funktioniert doch...

Wir suchen grade, weil ich behauptet habe, daß die Threads stehen und nix tun. Diese Aussage ist in der Tatsache begründet, daß die IDE (Debugger) immer noch die Threads als vorhanden anzeigt aber keine Aktivität zu verzeichnen ist. Normalerweise sollte die IDE nach Beendigung des ganzen ja in den Entwurfsmodus zurückkehren.

Es passiert folgendes:
- wenn ich das Programm ohne laufende Threads beende kommt die IDE in den Entwurfsmodus zurück
- Wenn ich das Programm mit laufenden Threads beende sieht es aus als ob eine Endlosschleife vorliegt.
- Beende ich den Task im Taskmanager kommt die IDE in dem Entwurfsmodus zurück.
- Starte ich nur die EXE wird der Task beendet.

... und das alles ohne Memory Leaks.

Kann das jemand erklären ?
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#15

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 12:10
Self.Start; innerhalb einer CriticalSection ???
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.300 Beiträge
 
Delphi 12 Athens
 
#16

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 12:16
macht keinen Unterschied...

Kommando zurück:
Beitrag 14 ist Quatsch.
- in der Schleife stand to statt downto
- Das FThreadList.Delete[1] stand außerhalb der Schleife.
Fazit: Das war wirklich eine Endlosschleife.

mal ein Auszug aus dem Ereignisprotokoll:
Delphi-Quellcode:
Thread-Start: Thread-ID: 292. Prozess XWebDemo.exe (6096) // normaler Threadstart
Thread-Start: Thread-ID: 5992. Prozess XWebDemo.exe (6096)// normaler Threadstart
Thread-Start: Thread-ID: 2520. Prozess XWebDemo.exe (6096)// normaler Threadstart
Thread-Ende: Thread-ID: 292. Prozess XWebDemo.exe (6096)// normales Ende
Thread-Ende: Thread-ID: 5992. Prozess XWebDemo.exe (6096)// normales Ende
Thread-Ende: Thread-ID: 2520. Prozess XWebDemo.exe (6096)// normales Ende
Thread-Start: Thread-ID: 5596. Prozess XWebDemo.exe (6096)// normaler Start
Thread-Start: Thread-ID: 5072. Prozess XWebDemo.exe (6096)// normaler Start
Thread-Start: Thread-ID: 5056. Prozess XWebDemo.exe (6096)// normaler Start --> Beenden geklickt
Quelltexthaltepunkt bei $005DF477: D:\Projekte\Delphi Unicode\XWeb500\DemoThreadVersion_1\XWebBase.pas Zeile 115. Prozess XWebDemo.exe (6096)
// while not (FThreadList.Count = 0) do
// siehe TXWeb.Destroy
// Schleife wird durchlaufen bis Liste leer...
// die Threads stehen, sonst wären sie schon fertig
Modul entladen: Security.dll. Prozess XWebDemo.exe (6096)
Modul entladen: WSHTCPIP.dll. Prozess XWebDemo.exe (6096)
Erste Gelegenheit für Exception bei $7C812AFB. Exception-Klasse EIdSocketError mit Meldung
'Socket Error # 10093 // Indy Meldung
'.
Prozess XWebDemo.exe (6096)
Erste Gelegenheit für Exception bei $7C812AFB. Exception-Klasse EIdSocketError mit Meldung
'Socket Error # 10093 // Indy Meldung
'.
Prozess XWebDemo.exe (6096)
Modul entladen: HNetCfg.dll. Prozess XWebDemo.exe (6096)
Thread-Ende: Thread-ID: 5072. Prozess XWebDemo.exe (6096) // erst hier werden die Threads beendet
Thread-Ende: Thread-ID: 5596. Prozess XWebDemo.exe (6096)
Thread-Ende: Thread-ID: 5056. Prozess XWebDemo.exe (6096)

Geändert von haentschman (10. Jan 2011 um 12:40 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.300 Beiträge
 
Delphi 12 Athens
 
#17

AW: mehrere Threads sauber beenden

  Alt 11. Jan 2011, 23:20
Kurze Rückmeldung...

mit Unterstützung von DeddyH sind wir auf folgendes Lösungsprinzip gekommen.

1. eine Liste für die Threads (hier als generische Liste unter XE)
Delphi-Quellcode:
TMyCustomThreadList = TList<TLoader>; // TLoader = class TThread

  TMyThreadList = class(TCustomThreadList)
  strict private
    FListHandle: HWND;
    FDestroying: Boolean;
    procedure TreadFinished(var Msg: TMessage); message PM_Finish_Thread; // Methode die die Message empfängt
  public
    constructor Create;
    destructor Destroy; override;
    procedure Clear;
    procedure Add(aThread: TLoader);
    procedure Remove(aThread: TLoader);
  end;
Delphi-Quellcode:
constructor TMyThreadList.Create;
begin
  inherited;
  // Fensterhandle erzeugen damit auch Messages enmpfangen werden können
  FListHandle := AllocateHWnd(TreadFinished);
end;
Delphi-Quellcode:
destructor TMyThreadList.Destroy;
begin
  Clear;
  DeAllocateHwnd(FListHandle);
  inherited;
end;
Delphi-Quellcode:
procedure TMyThreadList.Remove(aThread: TLoader);
begin
  aThread.Terminate;
  aThread.WaitFor;
  aThread.Free;
  inherited Remove(aThread);
end;
Delphi-Quellcode:
procedure TMyThreadList.Clear;
begin
  FDestroying:= True;
  while Count > 0 do
    Remove(Items[0]);
end;
Delphi-Quellcode:
procedure TMyThreadList.Add(aThread: TLoader);
begin
  inherited Add(aThread);
  aThread.ListHandle := FListHandle;
end;
2. Thread erzeugen und starten
Delphi-Quellcode:
  Loader:= TLoader.Create;
  // Zuweisung der Methode die nach der Arbeit des Threads ausgeführt wird (Methoden anpassen)
  Loader.OnFinish:= FinishLoad;
  FThreads.Add(Loader); // FThreads private Property von TMyThreadList
  Loader.Start; // Start gibts erst ab 2010 ? Ansonsten Resume;
3. Thread versendet User Message wenn fertig
Delphi-Quellcode:
const
  PM_Finish_Thread = WM_USER + 1;
.
.
// Methode die der TThread Methode OnTerminate zugewiesen ist
procedure TLoader.OnThreadTerminated(Sender: TObject);
begin
  PostMessage(FListHandle, PM_Finish_Thread, wParam(Self), 0);
end;
4. Message kommt an
Delphi-Quellcode:
procedure TXWebThreadList.TreadFinished(var Msg: TMessage);
begin
//FDestroying wird im destructor gesetzt, damit nicht 2 Mal entfernt wird. Wenn die Liste beim Beenden der
//Anwendung die Liste leer macht würde die Message ja auch ankommen.
  if (not FDestroying) and (Msg.Msg = PM_Finish_Thread) then
    Remove(TXWebLoader(Msg.wParam)); // Thread aus Liste entfernen und freigeben
end;
Fazit:
Der Unterschied besteht eigentlich nur darin, daß:
1. Der Thread über eine Message mitteilt daß er fertig ist. Nicht Ereignis. Ereignise werden sequentiell abgearbeitet und der Thread konnte sich nicht beenden solange die Ereignisse nicht abgearbeitet sind. Da war die Freigabe das Problem. Da kam die "Endlosschleife" her.
2. die Liste selbst die Threads entfernt und freigibt
3. dadurch daß jetzt WaitFor ordentlich funktioniert weil die Threads weiterlaufen (wegen Message) werden die Threads sauber beendet und freigegeben.

Hoffe, daß das Ganze anderen viel Nerven erspart...
  Mit Zitat antworten Zitat
mikaufmann

Registriert seit: 31. Mai 2011
1 Beiträge
 
#18

AW: mehrere Threads sauber beenden

  Alt 9. Dez 2013, 14:37
Hallo,
super ansatz mit messages zu arbeiten der funktioniert !!

nur ein kleiner tipfehler ist hier :

Postmessage(flisthandle,PM_FINISHED_THREAD,wparam( self),0);

sollte eigentlich heissen

Postmessage(flisthandle,PM_FINISHED_THREAD,wparam( sender),0);

sonst killt man den mainprocess
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 02:44 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