Entwickler-Ecke

Internet / Netzwerk - Indy HttpServer - manche Thread beenden sich nicht 98% CPU


DataCool - Mi 10.09.03 17:42
Titel: Indy HttpServer - manche Thread beenden sich nicht 98% CPU
Hi Leute,

ich habe ein großes Problem auf dem ich jetzt seit 2 Tagen rum reite und nicht weiter komme

Ich verwende in meiner App einen Indy(Version 9) IdHttpServer um Bilder zu einen Client zu übertragen. Der Client ist in diesem Falle ein Java-Script der eine bestimmte "Get-Anfrage" an den Server schickt, aber auch nur am Rande wichtig.

d.h. in meinen Server sind nur die Ereignisse

OnCommandGet u.
OnException

implementiert.

Jetzt das Wunder was mir so kopfzerbrechen bereitet :

Das ganze läuft eigentlich seit 4 Monaten wunderbar, natürlich mache ich an dem Rest des Programms ein paar Erweiterungen u. Bugfixing.
Jetzt hat sich nach meinen letzten Änderungen folgendes Problem ergeben :

Manchmal kommt es vor, das eine Anfrage zwar im OnConnect-Ereigniss landet , aber weder das Ereignis OnCommandGet, OnException, OnDisconnect tritt jemals für diesen Thread ein.
Das ganze wäre ja nicht so schlimm, wenn nicht beim ersten Auftreten dieses Phänomens die CPU-Belastung von 8% auf 98% steigt, wo sie dann auch bleibt.

Jetzt sagt Ihr bestimmt mach doch einfach die Änderungen rückgängig ! :mrgreen:

Das geht aber leider nicht, weil die App schon produktiv online ist und zweitens die Einstellungen des IdHttp-Server exakt die selben wie vorher sind und an der Handling Methode kann es auch nicht liegen, weil das Ereigniss OnCommandGet gar nicht eintritt.

Nach einem Tag Fehlersuche und mega-Hals hab ich mir gedacht :
Bau ich mir doch so ne Art Thread-Watch, der mir die toten Threads kickt. :idea:

Gesagt getan, doch wenn so ein Thread im Nirvana hängt lässt er sich auch nicht mit Terminate beeenden ? :autsch:

Ich weiss auch nicht warum er hängt, alles was ich sagen kann ist, das er das EReignis OnConnect sauber durchläuft, aber im OnCommandGet nicht ankommt und dann scheint er wohl in seiner eigenen Execute-Schleife im Kreis zu laufen und dabei nicht mal die Eigenschaft Terminated abzufragen.

Das einzige was auch noch seltsam ist, ist das wenn die den HttpServer auf active := false setze, wird der Thread gekillt.

Ich erwarte jetzt nicht das mir jemand aus dem Stehgreif den Fehlergrund bzw. die Lösung sagen kann.

Aber vielleicht hat jemand ne Idee wie ich der Sache auf den Grund gehen kann ? Denn sonst bekomm ich bald einen :puke: Krampf


Brueggendiek - Mi 10.09.03 23:46

Hallo!

Hier [http://www.swissdelphicenter.ch/de/forum/viewtopic.php?t=6942] stehen schon Antworten - aber auch in der Delphi-Praxis steht die Frage!

Sollte es sich beim Themenstarter etwa um eine neue Inkarnation des doofen Griffestellers handeln??
Zur Erklärung: wir hatten ja mal einen Multiposter namens TF - das kenne ich als Triebfahrzeug-Führer. Früher, als die noch was können mußten, nannte man das Lokführer. Heute sind das nur noch doofe Griffesteller (oder Handrad-Bediener).

Mit saurem Gruß

Dietmar Brüggendiek
@Mods: zumachen und Schlüssel bei Karlchen Hoesch aufbewahren lassen - im Hochofen!


DataCool - Do 11.09.03 09:33

@Brueggendiek:

1. Unter dem Link gibt es noch keine hilfreiche Antwort
2. Was spricht dagegen, das wenn man ein Mega-Problem in mehreren Foren hilfe sucht ? Bei einer Lösung wird die auch in alle Foren gepostet.
3. Oder soll das heissen, ich darf auch nur in einem Forum die Fragen von anderen Usern beantworten, obwohl das meistens auch überall die gleichen Probleme sind.

Also : Wo ist das Problem dabei ?


lemming - Do 11.09.03 10:19

Ich hab zwar nur dein Topic gelesen, aber probier es mit der Indy Komponente IdAntiFreeze.

-lemming


DataCool - Do 11.09.03 10:26

Die hab ich schon lange drauf ;-)

Wielleicht laufen bei mir einfach zu viele Threads parallel ab ?!

Es laufen 6 Threads im Hintergrund die alle im Intervall von ca. 1 Minute was tun, sonst schlafen die nur !
Es geht da meistens um Status-Meldungen an Server die per IdHttp an ein PHP-Script auf unserem Server gehen.

Totzdem Danke,

Data


DataCool - Do 11.09.03 12:27

Hi Leute,

ich konnte mein Problem selber lösen, trotzdem vielen Dank an alle die versucht haben zu helfen.

Ich habe das Problem mit der Holzhammer Methode gelöst ;-)

Ich haben meinem WebServer einen TIdThreadMgrPool hinzugefügt, das ist eine Komponente über die ich auf alle aktiven Threads zugreifen kann.

Jetzt habe ich mir zusätzlich folgende Klasse erzeugt :

Quelltext
1:
2:
3:
4:
5:
6:
7:
  THttpThreadInfo = class
    private
      fCreateTime : TDateTime;
    protected
    public
      property CreateTime : TDateTime read fCreateTime write fCreateTime;
  end;


Diese Klasse dient dazu, jeden Thread mit einem Erzeugungs-Zeitstempel zu versehen.

Jetzt bin ich bei der Methode OnConnect des WebServers hingegangen :

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TfrmMain.IdHTTPSvrConnect(AThread: TIdPeerThread);
Var  ThdInf  : THttpThreadInfo;
begin
  ThdInf := THttpThreadInfo.Create;
  ThdInf.CreateTime := now;
  AThread.Data := ThdInf;
         // Eintrag in meinem Logfile erzeugen ; Level 2
  logf.log('OnConnect Thread: '+inttostr(AThread.ThreadID),2);
end;


Jetzt habe ich einen Timer erzeugt der jede Sekunde folgende macht :

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
procedure TfrmMain.Tim_ThreadsTimer(Sender: TObject);
var i : Longint;
    tmpList : TList;
    tmpThd  : TIdPeerThread;
    ThdInf  : THttpThreadInfo;
begin
  lb_Threads.items.BeginUpdate;
  lb_Threads.items.Clear;
  tmpList := IdThreadMgrDefHttp.ActiveThreads.LockList;
  try
    for i:= 0 to tmpList.Count - 1 do begin
      if tmpList[i] <> nil then begin
        tmpThd := TIdPeerThread(tmplist[i]);
        if tmpThd.Data <> Nil then begin
          try
            ThdInf := THttpThreadInfo(tmpThd.Data);
            // läuft der Thread schon lange als 4 Sek. ?
            if ThdInf.CreateTime < (now - 4/24/60/60) then begin
              logf.log('Thread: '+inttostr(tmpThd.ThreadID)+' ist im Nirvana...',1);
              lb_Threads.items.Add('Thread Nr:'+inttostr(tmpThd.ThreadID)+'Status: Nirvana... auf Index: '+inttostr(i));
              //IdThreadMgrDefHttp.ReleaseThread(tmpThd);
              tmpThd.Connection.DisconnectSocket;
              //Wichtig, hier nicht terminate aufrufen geht sonst nicht !!
            end
            else
              lb_Threads.items.Add('Thread Nr:'+inttostr(tmpThd.ThreadID)+'Status: running auf Index: '+inttostr(i));
          except
            logf.log('Konnte Thread-Info nicht auslesen',1);
            //tmpThd.Terminate;
          end;
        end;
        //else
          //tmpThd.Terminate;
      end
      else
        lb_Threads.Items.Add('Nil Thread auf Index: '+inttostr(i));
    end;
  finally
    IdThreadMgrDefHttp.ActiveThreads.UnlockList;
    lb_Threads.items.EndUpdate;
  end;
end;


Durch die "Zwangstrennung" der Threads im "Nirvana" wird wieder das Ereignis OnDisconnect des WebServers ausgelöst :

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TfrmMain.IdHTTPSvrDisconnect(AThread: TIdPeerThread);
Var ThdInf  : THttpThreadInfo;
begin
  logf.log('OnDisconnect Thread: '+inttostr(AThread.ThreadID),2);
  if AThread.Data <> Nil then begin
    try
      ThdInf := THttpThreadInfo(AThread.Data);
    except
      ThdInf := Nil;
    end;
    if ThdInf <> Nil then begin
      ThdInf.free;
                           // !!! Wichtig, das Data-Objekt des Threads auf Nil setzen, sonst will der Thread den Speicher selber mit FreeAndNil freigeben, weil da ja noch ein Zeiger drin steht
      AThread.Data := nil;
    end;
  end;
end;


Im Kommentar habe ich ja schon erwähnt, das man das Data-Objekt unbedingt auf Nil setzen, muss damit der Thread den Speicher nicht versucht freizugeben.
Zuerst habe ich den Speicher meine ThreadInfo-Klasse nicht selber frei gegeben, weil ich dachte das das der Thread tut :

Quelltext
1:
2:
3:
4:
procedure TIdThread.Cleanup;
begin
  FreeAndNil(FData);
end;


Komischerweise habe ich dann ein "Memory-Leck" !!
Kamm mir jemand sagen warum ?

Gruß Data