AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language For-Schleife im Thread wird nur einmal abgearbeitet
Thema durchsuchen
Ansicht
Themen-Optionen

For-Schleife im Thread wird nur einmal abgearbeitet

Ein Thema von Captnemo · begonnen am 6. Jun 2014 · letzter Beitrag vom 19. Aug 2014
Antwort Antwort
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#1

For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 16:58
Delphi-Version: XE4
Hi,

ich habe einen Thread, mit eine IdTCPClient, der beim Start ein paar Daten aus dem Hauptprogramm senden soll.

Deswegen habe ich dort eine for-schleife, die aus dem Hauptprogramm Daten holt, und per TCP versenden soll. Mir ist schon klar, dass das alles vielleicht noch nicht ganz richtig ist, aber es handelt sich ja hier auch noch nicht um eine finale Version.
Ich greife auf eine ListView zu, und will für jedes Items eine TCP-Nachricht verschicken.
Im Count steht auch definiv 6 drin, aber die Schleife wird nur einmal durchlaufen.

Er senden auch genau dieses erste Item, bzw. einen String aus diesem Items.

Aber danach macht er nicht weiter, der Thread scheint auch nicht mehr zu reagieren, jedenfalls empfängt der TCPClient dann keine Nachrichten mehr.

Die ganze Writelog's müßt ihr euch mal wegdenken, die sind nur für mich da, damit ich sehen kann wann wer was macht (oder halt eben nicht).

Hier mal meine Execute-Procedure:

Delphi-Quellcode:
procedure TTCPThread.Execute;
var
  s,c: string;
  waage, command: string;
  i: Integer;
begin
  Try
    //FTCPClient.BoundIP:=FBindIP;
    //FTCPClient.BoundPort:=FBindPort;
    FTCPClient.host:=FHost;
    FTCPClient.Port:=FPort;
    FTCPClient.ConnectTimeout:=2000;
    Synchronize(
      Procedure
      begin
        frm_main.Writelog('Init TCP-Connection');
      end
    );
    FTCPClient.Connect;
    if not FTCPClient.Connected then
    begin
      Synchronize(
        Procedure
        begin
          frm_main.Writelog('TCP-Verbindung fehlgeschlagen');
        end
      );
      Self.Terminate;
    end else begin
      Synchronize(
        Procedure
        begin
          frm_main.Writelog('TCP-Verbindung hergestellt');
        end
      );
      //Diese Schleife wird genau einmal durchlaufen
      //Es sind 6 Items in lv_waagen vorhanden
      //Es wird aber lediglich lv_waagen.Items[0] verarbeitet
      FCS.Acquire;
      for I := 0 to frm_main.lv_waagen.Items.Count-1 do
      begin
        Synchronize(
          Procedure
          begin
            frm_main.Writelog('Sende Register '+inttostr(i)+' von '+inttostr(frm_main.lv_waagen.Items.Count-1));
          end
        );
        FTCPClient.SendCmd('Register:'+frm_main.lv_waagen.Items[i].SubItems[2]+':@');
      end;
      FCS.Release;
    end;
    while not Terminated do begin
      if FErgebnisList.Count>0 then
        SendeErgebnisse;
      if FTCPClient.IOHandler.InputBufferIsEmpty then
      begin
        FTCPClient.IOHandler.CheckForDataOnSource(100);
        FTCPClient.IOHandler.CheckForDisconnect;
        if FTCPClient.IOHandler.InputBufferIsEmpty then Continue;
      end;
      s:=FTCPClient.IOHandler.InputBuffer.ExtractToString;
      if s<>'then
      begin
          Synchronize(
            Procedure
            begin
              frm_main.Writelog(s + ' von '+ FHost);
            end
          );
          while Pos('@', s)>0 do
          begin
            c:=Copy(s,1,Pos('@',s)-1);
            s:=Copy(s,Pos('@',s)+1,Length(s));
            if Pos(':',c)>0 then
            begin
              command:=Copy(c,1,Pos(':',c)-1);
              c:=Copy(c,pos(':',c)+1,Length(c));
              waage:=Copy(c,1,Pos(':',c)-1);
              if lowercase(command)='stthen
              begin
                Synchronize(
                  procedure
                  begin
                     frm_main.NachrichtenBufferAdd(FHost, FPort, s, command, waage, self);
                  end
                );
              end;
            end;
          end;
      end;
      //Sleep(1000);
      Self.Suspend;
      if Terminated then
        break;
    end;
    if FTCPClient.Connected then begin
      FTCPClient.SendCmd('Disconnect');
      FTCPClient.Disconnect;
    end;
  finally
    if FTCPClient.Connected then begin
      FTCPClient.SendCmd('Disconnect');
      FTCPClient.Disconnect;
    end;
    FTCPClient.Free;
    FErgebnisList.Free;
    FCS.Free;
  end;
end;
Sieht alles noch sehr wüst aus, daran bitte nicht stören.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
mjustin

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

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:16
Funktioniert der Code denn auch wenn er nicht innerhalb eines Threads läuft?

Funktioniert es wenn die FCS (Critial Section) nicht benutzt wird? (Diese Critical Section in Verbindung mit einem Synchronize sieht nach einer Deadlockquelle aus).

Es ist wahrscheinlich nicht die Ursache für die Hänger, aber FTCPClient.IOHandler.InputBuffer.ExtractToString sieht bedenklich aus, hier kann auch ein Teil des erwarteten Inhalts im InputBuffer stehen. Die Daten können, wenn man das Protokoll kennt, mit IOHandler.Read... Methoden aus dem Socket gelesen werden. Wenn man das Protokoll nicht kennt, hat man ein anderes Problem
Michael Justin

Geändert von mjustin ( 6. Jun 2014 um 17:24 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:29
Da du im Execute keinerlei Exceptions verarbeitest, solltest du das dringend machen.
Try-Except drumrum und die Exception anzeigen.

Tipp: TThread hat ein OnTerminate-Ereignis, welches du dringend mal implementieren solltest, da du Ersteres ja nicht machst.
Und da drin dann einfach
Delphi-Quellcode:
if Assigned(TThread(Sender).FatalException) then
  ShowException(Exception(TThread(Sender).FatalException), nil);
Und nicht vergessen, dieser ShowException-Aufruf muß natürlich mit der VCL synchronisiert werden.

Ex gibt in der Unit System zwar ein End-Thread-Event, aber wenn Dieses ausgeführt wird, dann kann die Thread-Instanz schon weg sein (FreeOnTerminate) und selbst wenn noch nicht, dann kommt man dort sowieso nicht an den Instanzzeiger.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 6. Jun 2014 um 17:32 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.221 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:38
Da steht in der Methode ein FCS.Free aber kein FCS := <...>.Create!

Die Mehrfachen blöcke mit

Delphi-Quellcode:
        Synchronize(
          Procedure
          begin
            frm_main.Writelog('....');
          end
        );
Sollte man mindestens in eine Threadfähige Queue stecken um eine bessere Entkopplung zu haben.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:45
Zitat:
frm_main.lv_waagen.Items.Count
Und das ist auch threadsave?
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#6

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:51
Zitat:
frm_main.lv_waagen.Items.Count
Und das ist auch threadsave?
Sicherlich nicht. Zumindest zur Zeit. Aber
1. Der Thread ist der einzige der darauf zugreift (weil ich nur einen erzeuge)
2. Auf das lv_waagen wird nach dem Füllen nicht mehr zugegriffen, und dieses passiert definitiv vor dem Erzeugen des Threads.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von Captnemo
Captnemo

Registriert seit: 27. Jan 2003
Ort: Bodenwerder
1.126 Beiträge
 
Delphi XE4 Architect
 
#7

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 17:49
Hi,

die CriticalSection hab ich erst hinzugefügt, als ich gemerkt habe dass meine Schleife nicht vollständig durchlaufen wird. Vorher gings aber auch nicht.

das FTCPClient.IOHandler.InputBuffer.ExtractToString wird mit dem Fehler wohl nichts zu tun haben, denn mein Problem entsteht ja schon vorher.

ich kann auch mit 100%Prozentiger Sicherheit sagen, dass sich an meinem ListView während der Thread gestartet wird nicht verändert. Dieses wird aufgebaut, bevor der Thread gestartet wird und auch keiner Stelle im Prog verändert.

Interessant finde ich, dass
1. Auf dieses erste Item im LV ohne Fehler zugegriffen werden kann.
2. Auch der korrekte String gelesen wird
3. und diese auch von IdTCPClient korrekt versendet wird.

Nur warum es dann nicht weiter geht, das ist mir ein Rätsel.

Da du im Execute keinerlei Exceptions verarbeitest, solltest du das dringend machen.
Try-Except drumrum und die Exception anzeigen.

Tipp: TThread hat ein OnTerminate-Ereignis, welches du dringend mal implementieren solltest, da du Ersteres ja nicht machst.
Und da drin dann einfach
Delphi-Quellcode:
if Assigned(TThread(Sender).FatalException) then
  ShowException(Exception(TThread(Sender).FatalException), nil);
Und nicht vergessen, dieser ShowException-Aufruf muß natürlich mit der VCL synchronisiert werden.

Ex gibt in der Unit System zwar ein End-Thread-Event, aber wenn Dieses ausgeführt wird, dann kann die Thread-Instanz schon weg sein (FreeOnTerminate) und selbst wenn noch nicht, dann kommt man dort sowieso nicht an den Instanzzeiger.
Klingt logisch und einfach. Ist es sicherlich auch, wenn mal mit Threads viel Erfahrung hat. Leider muß ich da noch viel lernen und die Umsetzung fällt einem dann nicht immer so leicht.
Das mit Assigned(TThread(Sender).FatalException) hab ich grad mal gar nicht verstanden.
Dieter
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt. Die 10. summt dazu die Melodie von Supermario Bros.
MfG Captnemo
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 6. Jun 2014, 21:54
Klingt logisch und einfach. Ist es sicherlich auch, wenn mal mit Threads viel Erfahrung hat. Leider muß ich da noch viel lernen und die Umsetzung fällt einem dann nicht immer so leicht.
Das mit Assigned(TThread(Sender).FatalException) hab ich grad mal gar nicht verstanden.
Schau dir mal das OnTerminate-Event des TThread an. Das ist wie das OnClick der TButtons und im Sender steckt die Instand des angeklickten Buttons, also in diesem Fall natürlich die Instanz des beendeten Threads.

Ich weiß ja nicht wie ud wo die die Instanz deines Threads gespeichert hast, aber das ist ja egal, da der Sender immer passt und man die Instanz somit auch da auslesen kann.
Man muß halt nur das TObject in den richtigen Typen casten, wenn man das verwendet.


Ergebnis: Du erstellst dir eine passende Methode, rufst darin das Syncronize und auf darin dann den genannten Code.
Und nun natürlich nur noch das Event dem Thread zuweisen.

Delphi-Quellcode:
procedure TDeineForm{oder dein TThread-Nachfahre}.MyThreadTerminate(Sender: TObject);
begin
  // TThread(Sender).Synchronize nehm ich jetzt mal nicht, da der Thread ja eigentlich schon beendet ist
  // und ich jetzt nicht genau weiß, ob was passieren könnte, auch wenn es vermutlich doch funktionieren könnte
  TThread.Synchronize(nil, procedure
    begin
      if Assigned(TThread(Sender).FatalException) then
        ShowException(Exception(TThread(Sender).FatalException), nil);
    end);
end;

PS: Wäre es nicht besser, wenn dein WriteLog im inneren prüft, ob es im Hauptthread läuft und sich notfalls selber synchroonisiert?
(oder notfalls einfach immer blind synchronisieren ... das Synchronize prüft das intern bestimmt auch selber nochmal)
Würde das Logging vereinfachen und so einige Codezeilen sparen.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 6. Jun 2014 um 21:58 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: For-Schleife im Thread wird nur einmal abgearbeitet

  Alt 19. Aug 2014, 14:32
Da du im Execute keinerlei Exceptions verarbeitest, solltest du das dringend machen.
Try-Except drumrum und die Exception anzeigen.

Tipp: TThread hat ein OnTerminate-Ereignis, welches du dringend mal implementieren solltest, da du Ersteres ja nicht machst.
Und da drin dann einfach
Delphi-Quellcode:
if Assigned(TThread(Sender).FatalException) then
  ShowException(Exception(TThread(Sender).FatalException), nil);
Und nicht vergessen, dieser ShowException-Aufruf muß natürlich mit der VCL synchronisiert werden.

Ex gibt in der Unit System zwar ein End-Thread-Event, aber wenn Dieses ausgeführt wird, dann kann die Thread-Instanz schon weg sein (FreeOnTerminate) und selbst wenn noch nicht, dann kommt man dort sowieso nicht an den Instanzzeiger.
Klingt logisch und einfach. Ist es sicherlich auch, wenn mal mit Threads viel Erfahrung hat. Leider muß ich da noch viel lernen und die Umsetzung fällt einem dann nicht immer so leicht.
Das mit Assigned(TThread(Sender).FatalException) hab ich grad mal gar nicht verstanden.
TThread fängt Exceptions ab, welche im TThread-Execute aufgetreten und durchgerauscht sind (von dir nicht abgefangen werden -> Try-Except)
und dann veröffentlicht es diese Exception, über das Property FatalException, welches man im OnTerminate auslesen und anzeigen kann.

OnTerminate wird von TThread bereits mit der VCL synchronisert (ist eigentlich voll blöd, daß es immer automatisch passiert, denn man braucht/will das nicht immer so haben), also kann man darin problemlos direkt die Exception(MyThread.FatalException).Message anzeigen/loggen, oder man verwendet den Fehlerdialog der VCL (ShowException).


Windows beendet Programme (schießt sie hart ab), bei denen eine Exception bis zur Wurzel (Windows) durchrauscht.
Drum sollte man auch immer die SysUtils einbinden, um die Exception-Behandlung vom Delphi zu aktivieren.
Denn selbst wenn man eine kleine "billige" DLL hat, in Welcher (in exportierter Prozedur) eine Exception auftritt, dann würde Windows das Programm abschießen, da die DLL (standardmäßig) nicht weiß, ob sie in einem Delphi-Programm geladen ist und ob sie nicht vielleicht dessen Fehlerbehandlung mit benutzten könnte. (siehe Delphi-OH > Verwendung von DLLs)
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (19. Aug 2014 um 14:37 Uhr)
  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 06:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz