Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi TThread.Create erzeugt einen Stack Overflow? (https://www.delphipraxis.net/87590-tthread-create-erzeugt-einen-stack-overflow.html)

glkgereon 2. Mär 2007 16:02


TThread.Create erzeugt einen Stack Overflow?
 
Hi,

Ich bastel mal wieder mit Threads rum.

folgender Code:
Delphi-Quellcode:
TConnectThread = class(TThread)
  private
    FTCP: TIdTCPClient;
    FHost: String;
    FPort: Integer;
    FConnected: Boolean;
  public
    procedure Execute; override;
    property TCP: TIdTCPClient read FTCP write FTCP;
    property Host: String read FHost write FHost;
    property Port: Integer read FPort write FPort;
    property Connected: Boolean read FConnected;
  end;

procedure TConnectThread.Execute;
begin
  Priority:=tpLower;
  FConnected:=False;
  FTCP.Connect(FHost,FPort);
  FConnected:=True;
end;
Delphi-Quellcode:
  try
    CT:=TConnectThread.Create(True); <--
    CT.FreeOnTerminate:=True;
    CT.TCP:=Fidtcp;
    CT.Host:=Host;
    CT.Port:=Port;
    T:=GetTickCount+5000;
    CT.Resume;
Wenn ich das ganze so aufrufe wird bei TConnectThread.Create eine Exception geworfen welche da lautet "Stack Overflow".
Das ganze kann man auch mit einem TThread machen, es passiert das selbe.

Das ganze wird in keiner Rekursion, ja noch nichtmal in einer Schleif aufgerufen, von daher verstehe ich absolut nicht was das soll :cry:

Hat da irgendwer eine idee?

glkgereon 3. Mär 2007 16:57

Re: TThread.Create erzeugt einen Stack Overflow?
 
:? push :?

Christian Seehase 3. Mär 2007 17:39

Re: TThread.Create erzeugt einen Stack Overflow?
 
Moin Gereon,

ich kann das Problem weder mit D7, noch mit D2006 nachvollziehen.
Wenn es wirklich am Konstruktor liegt, müsste das Problem allerdings auch bei jedem der TThread benutzt geschehen.

Übrigens gehört das Setzen von Eigenschaften nicht in Execute sondern in Create, und die das, private, Feld FConnected zu in Execute zu setzen ist völlig überflüssig, wenn Du FreeOnTerminate auf true setzt.

glkgereon 3. Mär 2007 17:50

Re: TThread.Create erzeugt einen Stack Overflow?
 
Mir ist schon klar dass es nicht an TThread liegt....ich benutze im selben Programm auch noch nen anderen Thread, und der funktioniert...


Ich stehe hier echt völlig vor einer Wand.
wie gesagt: es ist eigentlich nichts da was den Stack wirklich füllen könnte und trotzdem kommt ein Overflow...immer :cry:

Hawkeye219 3. Mär 2007 18:05

Re: TThread.Create erzeugt einen Stack Overflow?
 
Hallo Gereon,

wenn CT eine Property mit einem Setter ist, könnte der Fehler dort zu suchen sein. Möglicherweise wird die Setter-Methode rekursiv aufgerufen.

Gruß Hawkeye

glkgereon 3. Mär 2007 18:14

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von Hawkeye219
Hallo Gereon,

wenn CT eine Property mit einem Setter ist, könnte der Fehler dort zu suchen sein. Möglicherweise wird die Setter-Methode rekursiv aufgerufen.

Gruß Hawkeye

*nachguck*

nein, leider nicht. CT ist eine Lokale variable.

Aber jetzt kommt schon bei diesem Code eine AV:

Delphi-Quellcode:
  if FIdTCP.Connected then Exit;
  try
    Fidtcp.Connect(Host,Port);
Statt dem ganzen Thread gedöhns drumherum...
Aber erst beim Connect...Die Überprüfung auf Connected geht anstandslos.

Zitat:

In Projekt <abc> trat ein Problem mit folgender Meldung auf: 'access violation at 0x004061f0: write of address 0x00030060'. Prozess angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
Jetzt bin ich total verwirrt.... :gruebel:

DGL-luke 3. Mär 2007 18:54

Re: TThread.Create erzeugt einen Stack Overflow?
 
Hat dein Thread keinen Konstruktor? bzw. wie sieht der aus?

glkgereon 3. Mär 2007 19:33

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von DGL-luke
Hat dein Thread keinen Konstruktor? bzw. wie sieht der aus?

nein, ich habe den von TThread nicht überschrieben.
Brauchte ich in dem Fall nicht.

Christian Seehase 3. Mär 2007 20:16

Re: TThread.Create erzeugt einen Stack Overflow?
 
Moin Gereon,

was passiert denn vor dieser Zeile:

Delphi-Quellcode:
CT:=TConnectThread.Create(True); <--
Ich vermute nämlich mal, dass die Ursache des Stack-Overflow an einer ganz anderen Stelle zu suchen ist, es dauert nur eine Weile, bis der Überlauf eintritt.
Auftreten kann der ja eigentlich nur durch ein nicht abbrechende Rekursion, ob die Rekursion nun absichtlich hervorgerufen wird, oder nicht.
Einer der "beliebtesten" Fehler in diesem Falle:
Innherhalb einer Getter-Methode einer Eigenschaft wird die Eigenschaft selber wieder gelesen.

glkgereon 3. Mär 2007 20:32

Re: TThread.Create erzeugt einen Stack Overflow?
 
Ok, also praktisch mal ein Backtrace was bis dahin passiert.
(Ich kann schonmal von vorneherein sagen: in meinem Code kommt weder eine Schleife noch eine absichtliche Rekursion vor... das mit den Gettern...nicht das es mir aufgefallen wäre)

Das ganze ist extrem gekürzt...
aber alles relevante sollte drin sein.

So, der ButtonClick
Delphi-Quellcode:
  TForm_Main = class(TForm)
  public
    I: TChatInterface;
    C: TChatClient;
  end;

procedure TForm_Main.FormCreate(Sender: TObject);
begin
  C.OnSleep:=Application.ProcessMessages;
end;

procedure TForm_Main.Btn_ConnectClick(Sender: TObject);
var ID: Integer;
    req: TChatDataPackage;
begin //Wir wollten unsern Client mit einem Server Verbinden
  if C.Connected then
  //Kommt nicht vor, wir sind noch nicht Connected...
  else
  begin
    ID:=I.ServerHistory.Add(Cmb_Hostname.Text); // Erstmal Servername speichern
    try
      C.Connect(I.ServerHistory[ID].Host,I.ServerHistory[ID].Port); //Verbinden
      req :=TChatDataPackage.Create('LOGIN',I.Profile.Nick,I.Profile.Passwd); //Login-Request Erstellen
      C.OnUserInput(req); //und absenden
      req.Free; //und wieder freigeben
    except
      on E: EConnectException do I.AddServer('Connection Failed'); //Wenns schiefgeht Fehlermeldung machen
    end;
  end;
  I.ServerHistory.Export2Strings(Cmb_HostName.Items); //Liste mit den Servern Updaten
end;
Aufgerufen wird zunächst C.Connected:
Delphi-Quellcode:
  TChatClient =class
    private
      Fidtcp: TIdTCPClient;
      FOnSleep: TOnSleep;
    public
      procedure Connect(Host: String; Port: Integer);
      function Connected: Boolean;
      property OnSleep: TOnSleep write FOnSleep;
  end;

procedure TChatClient.Connect(Host: String; Port: Integer);
var CT: TConnectThread;
    T: Cardinal;
    TT: TThread;
begin
  if FIdTCP.Connected then Exit;
  try
    CT:=TConnectThread.Create(True);
    CT.FreeOnTerminate:=True;
    CT.TCP:=Fidtcp;
    CT.Host:=Host;
    CT.Port:=Port;
    T:=GetTickCount+5000;
    CT.Resume;
    while (not CT.Terminated) do
    begin
      FOnSleep;
      if (T-GetTickCount<0) or (Fidtcp.Connected) then Break;
      Sleep(50);
    end;
    CT.Terminate;
    if not Fidtcp.Connected then raise EConnectException.Create('');
    FListeningThread.Resume;
  except
    raise EConnectException.Create('');
  end;
end;

function TChatClient.Connected: Boolean;
begin
  Result:=FIdTCP.Connected;
end;
Dann I.ServerHistory.Add
Delphi-Quellcode:
  TChatInterface = class (TObject)
  private
    FServerHistory: TServerHistory;
  public
    property ServerHistory: TServerHistory read FServerHistory;
  end;

type
  TServer = record
    Name: String;
    Host: String;
    Port: Integer;
  end;
  TServers = array of TServer;

  TServerHistory = class(TObject)
  private
    FItems: TServers;
    function Cmp(V1,V2: TServer): Integer;
  public
    function Add(S: String): Integer; overload;
    function Add(Name,Host: String; Port: Integer): Integer; overload;
    procedure Export2Strings(S: TStrings);
    property Items[ID: Integer]: TServer read GetItem; default;
  end;

function TServerHistory.Add(S: String): Integer;
var Name,Host: String;
begin //Ungeparsten Server in Liste schmeissen
  S:=Trim(S);
  if Pos('(',S)>0 then
  begin // "Name (Host:Port)"
    Name:=Copy(S,1,Pos(' (',S)-1);
    S:=Copy(S,Pos(' (',S)+2,Length(S)-Pos(' (',S));
  end;
  Host:=Copy(S,1,Pos(':',S)-1);
  Delete(S,1,Pos(':',S));
  Result:=Add(Name,Host,StrToInt(S));
end;

function TServerHistory.Add(Name, Host: String; Port: Integer): Integer;
var i, Akt, Hi, Lo: Integer;
    S: TServer;
begin //Server an sortierter Position einfügen
  S.Name:=Name;
  S.Host:=Host;
  S.Port:=Port;
  Hi:=High(FItems);
  Lo:=Low(FItems);
  if Hi<0 then Hi:=0;
  Akt:=Abs(Hi+Lo) div 2;
  while Hi-Lo<2 do
  begin //Richtige Stelle suchen
    i:=Cmp(FItems[Akt],S);
    case i of
      1: Hi:=Akt;
      0: Exit;
      -1: Lo:=Akt;
    end;
    Akt:=(Hi+Lo) div 2;
  end;
  SetLength(FItems,Length(FItems)+1);
  for i:=Akt to Length(FItems)-1 do
    FItems[i+1]:=FItems[i];
  FItems[Akt]:=S;
  Result:=Akt;
end;
Dann kommt C.Connect(I.ServerHistory[ID].Host,I.ServerHistory[ID].Port)
der Zugriff auf I.ServerHistory und C.Connect steht ja oben schon

SirThornberry 3. Mär 2007 21:26

Re: TThread.Create erzeugt einen Stack Overflow?
 
hast du dir den schonmal den "CallStack" angeschaut? Wie sieht der aus wenn der Fehler kommt (Stack overflow)

glkgereon 3. Mär 2007 21:33

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von SirThornberry
hast du dir den schonmal den "CallStack" angeschaut? Wie sieht der aus wenn der Fehler kommt (Stack overflow)

Zitat:

TChatClient.Connect('*wuppdi*',9020)
TForm_Main.Btn_ConnectClick(???)
:0044d8ce TControl.Click + $6A
:00450b8b TWinControl.WndProc + $20B
:00450cc4 DoControlMsg + $28
:00450b8b TWinControl.WndProc + $20B
:004234d6 StdWndProc + $16
:77e3158f ; G:\WINNT\system32\user32.dll
:77e2b7a9 ; G:\WINNT\system32\user32.dll
:77e2b811 user32.SendMessageW + 0x49
:77e28126 ; G:\WINNT\system32\user32.dll
:77e17ae2 user32.DefWindowProcA + 0xa8
:77e3158f ; G:\WINNT\system32\user32.dll
:77e2afa1 user32.VkKeyScanW + 0x5f
:77e17e2d user32.CallWindowProcA + 0x1b
:00450c70 TWinControl.DefaultHandler + $DC
:00450b8b TWinControl.WndProc + $20B
:004234d6 StdWndProc + $16
:77e3158f ; G:\WINNT\system32\user32.dll
:77e31dc9 ; G:\WINNT\system32\user32.dll
(Das ist alles.... Nun einmal F7 und Overflow...)

mr2 3. Mär 2007 21:42

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von glkgereon
Zitat:

Zitat von DGL-luke
Hat dein Thread keinen Konstruktor? bzw. wie sieht der aus?

nein, ich habe den von TThread nicht überschrieben.
Brauchte ich in dem Fall nicht.


Zitat:

Zitat von glkgereon
Aber jetzt kommt schon bei diesem Code eine AV:

Delphi-Quellcode:
  if FIdTCP.Connected then Exit;
  try
    Fidtcp.Connect(Host,Port);
Zitat:

In Projekt <abc> trat ein Problem mit folgender Meldung auf: 'access violation at 0x004061f0: write of address 0x00030060'. Prozess angehalten. Mit Einzelne Anweisung oder Start fortsetzen.

Du solltest FTCP auch irgendwo (am besten im Konstruktor :)) erzeugen, wenn es sich dabei um ein Objekt handelt, sonst bekommst Du zwangsläufig eine Zugriffsverletzung.

mr2

glkgereon 3. Mär 2007 21:45

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von mr2
Du solltest FTCP auch irgendwo (am besten im Konstruktor :)) erzeugen, wenn es sich dabei um ein Objekt handelt, sonst bekommst Du zwangsläufig eine Zugriffsverletzung.

mr2

*möp*
Delphi-Quellcode:
procedure TChatClient.Connect(Host: String; Port: Integer);
var CT: TConnectThread;
    T: Cardinal;
    TT: TThread;
begin
  if FIdTCP.Connected then Exit;
  try
    CT:=TConnectThread.Create(True);
    CT.FreeOnTerminate:=True;
    CT.TCP:=Fidtcp; // <-- !!!
    CT.Host:=Host;
    CT.Port:=Port;
    T:=GetTickCount+5000;
    CT.Resume;
    while (not CT.Terminated) do
    begin
      FOnSleep;
      if (T-GetTickCount<0) or (Fidtcp.Connected) then Break;
      Sleep(50);
    end;
    CT.Terminate;
    if not Fidtcp.Connected then raise EConnectException.Create('');
    FListeningThread.Resume;
  except
    raise EConnectException.Create('');
  end;
end;

Christian Seehase 3. Mär 2007 22:05

Re: TThread.Create erzeugt einen Stack Overflow?
 
Moin Gereon,

FidTCP solltest Du im Thread allerdings per Synchronize verwenden.
Es ist ja eine Kompo des Hauptthreads.

glkgereon 3. Mär 2007 22:57

Re: TThread.Create erzeugt einen Stack Overflow?
 
Zitat:

Zitat von Christian Seehase
Moin Gereon,

FidTCP solltest Du im Thread allerdings per Synchronize verwenden.
Es ist ja eine Kompo des Hauptthreads.

Wie würde das konkret aussehen?
so?
Delphi-Quellcode:
Synchronize(FTCP.Connect(FHost,FPort));
Edit:
So müsste es doch richtig sein, oder?
Delphi-Quellcode:
procedure TConnectThread.SyncConnect;
begin
  FTCP.Connect(FHost,FPort);
end;

procedure TConnectThread.Execute;
begin
  Priority:=tpLower;
  FConnected:=False;
  Synchronize(SyncConnect);
  FConnected:=True;
end;
(Stack Overflow bleibt)

glkgereon 5. Mär 2007 16:42

Re: TThread.Create erzeugt einen Stack Overflow?
 
Sooo, also einiges hat sich geklärt...

Zum einen habe ich eine AV-Quelle gefunden in meinem Sortiert-Einfügen für die ServerHistory.
Dann war das ganze eine Debugger-Exception...Naja, ich hab Delphi neuinstalliert und es scheint weg zu sein.

von daher ist mein Ursprungsproblem behoben...
Naja, das dieses Threads zumindest :???:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:12 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