Delphi-PRAXiS
Seite 5 von 7   « Erste     345 67      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Thread.Queue, Zeitmessung, Thread hängt angeblich (https://www.delphipraxis.net/217196-thread-queue-zeitmessung-thread-haengt-angeblich.html)

Kas Ob. 21. Mai 2025 13:42

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1548803)
Ich versuche auf einige Fragen zu antworten aber das Senden mit UDP hin und her mit softwareseitiger Quittierung funktioniert ja. OHNE VCL Hänger.
Der UDPServer ist ein Thread und empfängt die Daten.
Für jeden UDP Teilnehmer im Netzwerk (=Client), erzeuge ich mir im Server einen eigenen Thread, der dann das Senden an den Client übernimmt (dieser heißt bei mir Client-Thread und ist natürlich ein TThread).
Das Senden macht NICHT der Server-Thread direkt. Der Server gibt dem Client-Thread nur die Hostadresse und Port (vom Empfang) mit.
Im Client-Thread wird ein IdUDPClient erstellt, welcher das Senden übernimmt an Host und Port. Der Client-Thread überwacht auch selber die Quittierung der UDP Telegramme. Daher braucht sich die Server-Komponente NUR um den Empfang kümmern.
Der Datenaustausch mit dem Client-Endgerät, wird durch einen Client-Thread gemacht.
Der Client-Thread überwacht seine MessageQueue mit besagter PeekMessage-Technik und wenn für eine gewisse Zeit, keine Daten mehr eintreffen, wird der Teilnehmer als offline erkannt und der Client-Thread terminiert sich mit ".Terminate"

IdUDPClient is a component, did you assign an owner for it ? if yes then this might explain a lot.

IN all cases IdUDPClient is overkill as i explained the from that initial event fired on server side you already have the connection (what called a distinguish identifier for UDP client) along a way to send using SendTo, so introducing IdUDPClient triggering threads that is competing with the server over this connection, is an overhead approach.

Now about that last line, your timeout at 250ms monitoring messages is to switch between
1) check if a message is received then what, either timed out at 250ms which contradict the need for real time or
2) try to read from the client ? or send ?

Still the whole design is not clear.

Just handle the packets in the one recv thread then send from it, even if it is the server triggered event OnRead, because there is something is triggering the main thread to perform some work (a lot of work), and even after all what did you described, this doesn't explain the main thread business.

AJ_Oldendorf 21. Mai 2025 14:14

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
IdUDPClient liegt auf einem Datenmodul welches mit
Delphi-Quellcode:
.Create(Nil);
erzeugt wird.
Also nein, es hat keinen Owner.

Das Senden mit IdUDPClient sieht so aus:
Delphi-Quellcode:
IdUDPClient.SendBuffer(MyDModul.IdUDPClient.Host,
                       MyDModul.IdUDPClient.Port,
                       ByteMsg);
Eine Prüfung genau an dieser Stelle auf "MainThreadID" und "GetCurrentThreadID" sagt auch, KEIN VCL Kontext.

Das Thema mit den 250ms ist in dem Verarbeitungsthread, hat nichts mit dem Client-Thread zu tun! Das Thema sollten wir nicht weiter betrachten.

Richtig, dass Hauptproblem ist nach wie vor die hängende VCL für ~ 7s.
Interessant ist, es sind wirklich immer ~ 7s, bei jedem Test.

Gibt es eine Möglichkeit, dass ich selber herausbekomme, was der VCL Kontext/Thread gerade gemacht? Ich glaube nämlich nicht, dass das UDP Thema damit eine Rolle spielt. Ich kann es nur dadurch erzeugen, da ich damit so viele Threads gleichzeitig beende.

Edelfix 21. Mai 2025 14:28

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Weil ich Indy sehe muss ich an TIdAntiFreeze denken.

Bin mir aber nicht sicher ob das an dieser Stelle hilfreich ist.

himitsu 21. Mai 2025 14:49

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Aber nur wenn man es im Hauptthread verwendet, was hier ja wohl nicht vorkommt.

Kas Ob. 21. Mai 2025 15:13

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1548805)
IdUDPClient liegt auf einem Datenmodul welches mit
Delphi-Quellcode:
.Create(Nil);
erzeugt wird.
Also nein, es hat keinen Owner.

Das Senden mit IdUDPClient sieht so aus:
Delphi-Quellcode:
IdUDPClient.SendBuffer(MyDModul.IdUDPClient.Host,
                       MyDModul.IdUDPClient.Port,
                       ByteMsg);
Eine Prüfung genau an dieser Stelle auf "MainThreadID" und "GetCurrentThreadID" sagt auch, KEIN VCL Kontext.

Das Thema mit den 250ms ist in dem Verarbeitungsthread, hat nichts mit dem Client-Thread zu tun! Das Thema sollten wir nicht weiter betrachten.

Richtig, dass Hauptproblem ist nach wie vor die hängende VCL für ~ 7s.
Interessant ist, es sind wirklich immer ~ 7s, bei jedem Test.

Gibt es eine Möglichkeit, dass ich selber herausbekomme, was der VCL Kontext/Thread gerade gemacht? Ich glaube nämlich nicht, dass das UDP Thema damit eine Rolle spielt. Ich kann es nur dadurch erzeugen, da ich damit so viele Threads gleichzeitig beende.

Saying killing so many threads at once can cause this, make my sad.
Here a simple test that will create 50000 threads and exits them, no killing just exit gracefully, creating them in fraction of second and exit them in second(s):
Delphi-Quellcode:
unit Unit10;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm10 = class(TForm)
    Timer1: TTimer;
    Label1: TLabel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    procedure CreateOneThread;
    procedure CreateThreads(Count: Integer);
  public
    { Public declarations }
  end;

var
  Form10: TForm10;

implementation

{$R *.dfm}

var
  CurrentThreadCount: Integer;

const
  CREATE_MANY_THREADS = 50000;
  THREADS_STACK_SIZE = 64 * 1024;
  STACK_SIZE_PARAM_IS_A_RESERVATION = $00010000;

function ThreadFunc(Parameter: Pointer): Integer;
begin
  InterlockedIncrement(CurrentThreadCount);
  Sleep(4000);
  InterlockedDecrement(CurrentThreadCount);
  EndThread(0);
end;

procedure TForm10.FormCreate(Sender: TObject);
begin
  Timer1.Interval := 50;
end;

procedure TForm10.CreateOneThread;
var
  ThreadId: Cardinal;
  ThreadHandle: THandle;
begin
  ThreadHandle := BeginThread(nil, THREADS_STACK_SIZE, Addr(ThreadFunc), 0, STACK_SIZE_PARAM_IS_A_RESERVATION, ThreadId);
  if ThreadHandle <> 0 then
    CloseHandle(ThreadHandle);
end;

procedure TForm10.CreateThreads(Count: Integer);
begin
  while Count > 0 do
  begin
    CreateOneThread;
    Dec(Count);
  end;
end;

procedure TForm10.Button1Click(Sender: TObject);
begin
  if IsDebuggerPresent then
    CreateThreads(10)
  else
    CreateThreads(CREATE_MANY_THREADS);
end;

procedure TForm10.Timer1Timer(Sender: TObject);
begin
  Label1.Caption := IntToStr(CurrentThreadCount);
end;

end.
Build it for 64bit not 32bit, and don't run it in the debugger as it will kill the IDE, try to increase the created and exited threads to 100k, will there be a big difference.

Anyway all Indy components are tied internally to singletons that track their creation and lifetime, using CciticalSection and try to look for singleton that protect from hanging and freezing also for logging...etc..
I am not expert on Indy but you approach even with 35 connection is wrong and cause this.

Away from that there is no solution like put this line and it will work fine.

ps: when running that test of 50k threads watch the red against the green in Process Explorer.

Kas Ob. 21. Mai 2025 15:20

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Zitat von himitsu (Beitrag 1548808)
Aber nur wenn man es im Hauptthread verwendet, was hier ja wohl nicht vorkommt.

I am pretty much sure it is the main thread problem to begin with, as UDP server is most likely a dropped component on a form or module, this one is creating the socket and listening to the traffic then later another TIdUDPClient form different thread is creating socket and trying to perform recv from the same address, leaving them both competing on shared resource.

The question AJ_Oldendorf did not answer, are there any sort of Synchronize or Thread control functions/method from "TThread." being used ?
is there from TThread beyond Create and Execute being used ? like WaitFor ...

AJ_Oldendorf 22. Mai 2025 05:55

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Saying killing so many threads at once can cause this, make my sad.
Here a simple test that will create 50000 threads and exits them, no killing just exit gracefully, creating them in fraction of second and exit them in second(s):
Ich habe nicht verstanden, was mir das Beispiel helfen soll.
Es geht bei mir um 35 Threads, nicht um 50000.
Meine Threads sind Objekte vom Typ TThread und werden mit TThread.Create() erstellt.
Warum sind es 35 einzelne Threads mit jeweils einer UDPClient Komponente? Jeder Thread und jeder Teilnehmer, kann zu unterschiedlichen Zeiten unterschiedliche Daten geschickt bekommen. Wird alles in einem Thread abgewickelt wird, müssen sich alle Telegramme durch eine UDPClient-Komponente quälen, so kann jeder Thread an seinen jeweiligen Empfänger (dies ist natürlich auch immer ein anderer, also 35 verschiedene Empfänger) losgelöst arbeiten.

Zitat:

I am pretty much sure it is the main thread problem to begin with, as UDP server is most likely a dropped component on a form or module, this one is creating the socket and listening to the traffic then later another TIdUDPClient form different thread is creating socket and trying to perform recv from the same address, leaving them both competing on shared resource.

The question AJ_Oldendorf did not answer, are there any sort of Synchronize or Thread control functions/method from "TThread." being used ?
is there from TThread beyond Create and Execute being used ? like WaitFor ...
Ich dachte alle Fragen beantwortet zu haben aber hier nochmal zur Klarstellung.
Es wird kein Synchronize im Programm verwendet. Es wird kein WaitFor... im Programm verwendet. Class functions/method von "TThread." (wie TThread.Queue) wird nicht verwendet. Ich habe reine Variablen/Objekte vom Typ TThread und die werden mit .Create erstellt und nur über den Variablennamen darauf zugegriffen.

Ich möchte nochmal auf das Hauptproblem zurück kommen.
VCL Hänger.
Wie kann ich in meinem Programm selbstständig feststellen, wer die VCL blockieren könnte bzw was der VCL Thread aktuell macht.
Vielleicht wird ja auch aus irgendeinen unbekannten Grund, eine rechenintensive Funktion durch den VCL Thread bearbeitet, was natürlich auch den Hänger erklären würde

shebang 22. Mai 2025 08:10

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1548834)
Wie kann ich in meinem Programm selbstständig feststellen, wer die VCL blockieren könnte bzw was der VCL Thread aktuell macht.

Du lässt das Programm im Debugger laufen und während des VCL Hängers pausiert du den Debugger. Aus der Threadliste suchst du dir dann den VCL Thread heraus und guckst dir im Stacktrace an, in welcher Funktion er steckt. Je nachdem was er gerade macht, musst du das ein paar mal wiederholen.

Kas Ob. 22. Mai 2025 08:55

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
That example shows how threads are magnificent beasts on Windows, 50k are feather light in creating and exiting, (notice it might be translation problem as i read killing threads), yet it takes only 4 on my 4-core CPU to destroy my whole OS experience, the example is to show you you are after the wrong reason, creating and exiting threads is fast.

Zitat:

Zitat von AJ_Oldendorf (Beitrag 1548834)
Ich möchte nochmal auf das Hauptproblem zurück kommen.
VCL Hänger.
Wie kann ich in meinem Programm selbstständig feststellen, wer die VCL blockieren könnte bzw was der VCL Thread aktuell macht.
Vielleicht wird ja auch aus irgendeinen unbekannten Grund, eine rechenintensive Funktion durch den VCL Thread bearbeitet, was natürlich auch den Hänger erklären würde

Same as my first post in this thread, use a profiler and it will pin point the long VCL operation.

See you insist on creating one UDPClient per connection on a server, that is wrong, you said you are not assigning and owner, yet in the same phrase they are on DataModule
Zitat:

IdUDPClient liegt auf einem Datenmodul welches mit .Create(Nil); erzeugt wird.
Also nein, es hat keinen Owner.
It could be something missed in translation.

My final words here is, there is no unknown reason for this, there is broken logic and false assumptions, so no, not Windows faults, not network adapter faults, and not Delphi RTL/VCL fault.
Remove the UDPClient creation, make sure you are not creating TDataModule with punch of components on it per client, simplify the logic into one thread per one client doing it all and this freeze will disappear.

AJ_Oldendorf 22. Mai 2025 09:33

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Zitat:

Du lässt das Programm im Debugger laufen und während des VCL Hängers pausiert du den Debugger. Aus der Threadliste suchst du dir dann den VCL Thread heraus und guckst dir im Stacktrace an, in welcher Funktion er steckt. Je nachdem was er gerade macht, musst du das ein paar mal wiederholen.
Danke, dass werde ich versuchen.

Zitat:

Same as my first post in this thread, use a profiler and it will pin point the long VCL operation.
Ich wollte es gerne nach Möglichkeit gerne selber erkennen und keine Fremdsoftware dafür installieren.

Zitat:

See you insist on creating one UDPClient per connection on a server, that is wrong, you said you are not assigning and owner, yet in the same phrase they are on DataModule
Ich habe es auch ohne Datenmodul versucht und die UDPClient Komponente als Variable im Threadobjekt deklariert. Das hat kein Unterschied ausgemacht. Liegt also nicht daran.

Ich sage auch nicht, dass Beenden von Threads generell lange dauert. Das wäre sicherlich schon jemanden vor mir aufgefallen, wenn es denn so wäre :-D Ich sage nur, wie ich es erzeugen kann, woran es tatsächlich liegt, suche ich ja noch


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:06 Uhr.
Seite 5 von 7   « Erste     345 67      

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