AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Thread.Queue, Zeitmessung, Thread hängt angeblich
Thema durchsuchen
Ansicht
Themen-Optionen

Thread.Queue, Zeitmessung, Thread hängt angeblich

Ein Thema von AJ_Oldendorf · begonnen am 20. Mai 2025 · letzter Beitrag vom 26. Mai 2025
Antwort Antwort
Seite 1 von 2  1 2      
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#1

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

  Alt 21. Mai 2025, 05:47
Guten Morgen,
also nochmal grob erklärt und zusammengefasst:
Es sind ca 35 UDP Teilnehmer an der Anwendung angemeldet (die Anwendung ist ein UDP Server und empfängt die Daten im OnUDPRead Event der Indy Komponente). Jeder UDP Teilnehmer ist ein eigener Thread da dieser losgelöst kommunizieren kann von den anderen.
Meine Threadinstanz, wo ich das Problem mit der Zeitmessung habe, bekommt die Daten von dem jeweiligen UDP Thread geschickt via "PostThreadMessage".

Diese Threadinstanz (existiert also auch 35x, da 35 UDP Teilnehmer online sind), empfängt die Daten in ihrer ThreadQueue grob durch folgenden Aufruf:

Delphi-Quellcode:
while not Terminated do
begin

  //hier erfolgt eine Signalisierung über WaitForSingleObject und bei Timeout (=250ms), erfolgt der zyklische Aufruf unten
  if WaitForsingleObject(Irgendwas, 250, xxxx) = WAIT_OBJECT_0 do
  begin

  end;

  //zyklischer Aufruf
  var sw := TStopwatch.StartNew;
  var TC : DWORD;
  TC := GetTickCount;

  //Synchronize(MeineFunktion);
  //Queue(Nil, MeineFunktion);
  //ForceQueue(Nil, MeineFunktion);

  t1 := sw.ElapsedMilliseconds;
  //Protokollierung von t1 ...

  TC2 := GetTickCount - TC;
  //Protokollierung von TC2 ...
end;
Die Protokollierung der Zeitmessung sowohl von t1 als auch TC2, schlägt zu. Egal welcher der 3 Aufrufe genutzt wird.
Eine Prüfung vorher auf if (MainThreadID <> GetCurrentThreadID) then zeigt auch, dass es nicht der VCL Thread ist als Aufrufer.
Die Protokollierung innerhalb der Funktion "MeineFunktion" schlägt nicht zu.

Ich muss weitere Untersuchungen anstellen, da auch ein Ausklammern der Funktion "MeineFunktion" dazu führt, dass die VCL hängt. Synchronize Aufrufe habe ich keine mehr im Programm. Ich muss prüfen, wer die VCL blockiert. Eurekalog habe ich schon mal installiert aber bei HangDetection wurde mir nichts angezeigt bzw. wann wird da wo was angezeigt? In dem Moment wo die Anwendung hängt oder beim Beenden?
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#2

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

  Alt 21. Mai 2025, 07:14
Edit:
Habe mir das OnIdle Event der Anwendung mal protokolliert und das kommt 7s nicht, genau in dem Zeitraum, wo die VCL auch hängt
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
2.058 Beiträge
 
Delphi 12 Athens
 
#3

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

  Alt 21. Mai 2025, 08:37
Was passiert wenn du mehr "PostThreadMessage" ausführst als in den 35 threads und dem Protocoll thread und dem Hauptthread ausgefürht werden können?
Gibt es ein Maximum and Queue size? Oder ist die Queue irgendwann Greedy und will abgearbeitet werden bevor neue Messages auflaufen?
Gibt es da einen Mechanismus in der Art der zum tragen kommen könnte?

Was wenn du von Threads auf Tasks(ITask) umsteigst, oder ist da kein effizenz Gewinn möglich da du eh schon mit nem Threadpools arbeitest?
Andreas
Nobody goes there anymore. It's too crowded!
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
457 Beiträge
 
#4

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

  Alt 21. Mai 2025, 09:00
Now i am more confused than before, sorry.

You did not explain what is going on, as you still abusing Indy and its threads !

1) Your server is using multithread to handle UDP connections, that is fine and is in fact the right way, BUT as you did again miss the explaining what exactly and how you handle these received UDP packets, i will assume you are handling them all in the main thread and enforcing this by these
Delphi-Quellcode:
  //Synchronize(MeineFunktion);
  //Queue(Nil, MeineFunktion);
  //ForceQueue(Nil, MeineFunktion);
Congratulations, you defeated the whole purpose of using multithread server to handle connections, and you are better to switch to event based server and handle everything in the main thread.
The whole approach of using or receiving packets and handling in the main thread, is to not block packet handling and absolve the main thread to handle UI.
But this is based on what i see from the code you pasted, the same code without more details, like where the UDP packers read is happening.

2) What on earth this WaitForsingleObject is used for ?, what the idea of it ? purpose ? and it is inside the thread execution loop ? that can't be more wrong on so many level, it is like you have one wheel but only interacting with it with stick(s).

3) You confirming the TC, yet i still see TC2, and don't see where these variables declared are they all local to this thread ? how are you logging ?

4) you mentioned PostThreadMessage, how this fit in all of this, you either use PostThreadMessage or one of these
Delphi-Quellcode:
  //Synchronize(MeineFunktion);
  //Queue(Nil, MeineFunktion);
  //ForceQueue(Nil, MeineFunktion);
never together, well you can, but nothing good is coming out of it.

5) OnIdle is taking 7 seconds, is clear evidence of you killing the main thread, now you said the CPU is not high or no CPU usage, so let me explain how modern CPU(s) work, one thread will run on one core at any moment, so main thread is hugged or and on full job, then one core will go 100%, if you look on you overall CPUusage and it is 4 cores, then it will show 25%, if you CPU 8 then it will show %12 ....
So look again how much your main thread is utilizing.

6) THe fact Process Explorer showing too much red, and from your screenshot, i pointed that kernel time is multiple over user time, is clear that main thread is put to handle IO or something has to do with kernel operation, what is it ?

Here an example on how to handle UDP, it is this simple and don't complicate things, https://stackoverflow.com/questions/...simple-strings

Know this : You can receive thousands of packets of hundreds clients per seconds on main thread and it will not glitch for fraction of seconds, as you don't handle or process these packets just receive, so either receive everything in main thread then signal few threads to process, or receive in background thread and handle them there, never in main thread.

Main thread is not super thread or faster than any other threads, on contrary it is burdened with UI handling, so less job for it,

ps :
7) are you logging in main thread ? how many operation per second ? also how many packets you do receive per seconds ?
Kas
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#5

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

  Alt 21. Mai 2025, 09:56
PostThreadMessage wird sicherlich noch an anderen Stellen aufgerufen, da dies ja eine Nachricht an ein bestimmten Thread ist (mit Angabe des ThreadHandles wird PostThreadMessage aufgerufen).

ITask habe ich noch nie benutzt und wüsste jetzt auch nicht, warum man das umstellen sollte?! Vor- und Nachteile?

@Kas Ob.
Ich versuche nur auf ein Bruchteil zu antworten, da meiner Meinung nach Fragen dabei sind, die nichts damit zu tun haben.

Die IdUDPServer Komponente ruft das OnUDPRead Event auf. Dort werden die Nachrichten an die entsprechenden Clients-Threads weitergeleitet.
Der Aufruf des OnUDPRead Events erfolgt NICHT in der VCL.
Geprüft durch Abfrage if (MainThreadID <> GetCurrentThreadID) then Die Threads empfangen die Nachrichten und machen damit etwas.
Auf das erfolgt nicht in der VCL.

Ich sage auch nicht, dass es am UDP hängt! Ich bekomme es nur damit nachgestellt. Es hängt definitiv die VCL (siehe IdleEvent). Eventuell ist auch etwas anderes Schuld. Synchronize Aufrufe sind KEINE im Programm.
CPU Auslastung vom MainThread ist laut Prozessexplorer 0.05, während die Anwendung hängt!
Mein Rechner hat 24 Kerne, eine volle Auslastung wären demnach 4%, welche ich aber NICHT habe.

Kleine Korrektur, es ist nicht "WaitForsingleObject" sondern "MsgWaitForMultipleObjects".
Wenn der Returnwert = WAIT_OBJECT_0 ist, wird die Thread-Queue abgearbeitet mit while PeekMessage(MessageData, 0, 0, 0, PM_REMOVE) do Ja, alle Variablen für die Zeitmessung sind lokal. Ich hatte TC2 vergessen mit in dem Codeschnipsel zu schreiben. Ist ja nur ein Ausschnitt des Codes und da hatte ich TC2 übersehen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

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

  Alt 21. Mai 2025, 10:30
Die ThreadQueue hat ein Limit (keine Ahnung wie groß)
und wenn voll, dann wird beim PostThreadMessage/PostMessage/SendMessage die Eintragung verworfen und diese Funktionen geben einen Fehlercode zurück.

Jeder Thread hat seine eigene Queue, welche beim ersten Zugriff erzeugt wird.
Statt einer GDI-Queue könnte man z.B. eine TThreadList verwenden. (bzw. es gibt auch irgendwo threadsichere TQueueIrgendwas und TStackIrgendwas im Delphi)
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#7

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

  Alt 21. Mai 2025, 10:51
PostThreadMessage habe ich immer auf das Result abgefragt und dies ist nie False, also immer erfolgreich gewesen.

Hier auch nochmal als Beweis eine Protokollierung im OnUDPRead Event:

AThread.ThreadID: 30856
MainThreadID: 32612
GetCurrentThreadID: 30856

Also wird es nicht im Hauptthread empfangen und verarbeitet
  Mit Zitat antworten Zitat
Kas Ob.

Registriert seit: 3. Sep 2023
457 Beiträge
 
#8

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

  Alt 21. Mai 2025, 10:52
PostThreadMessage wird sicherlich noch an anderen Stellen aufgerufen, da dies ja eine Nachricht an ein bestimmten Thread ist (mit Angabe des ThreadHandles wird PostThreadMessage aufgerufen).

ITask habe ich noch nie benutzt und wüsste jetzt auch nicht, warum man das umstellen sollte?! Vor- und Nachteile?

@Kas Ob.
Ich versuche nur auf ein Bruchteil zu antworten, da meiner Meinung nach Fragen dabei sind, die nichts damit zu tun haben.

Die IdUDPServer Komponente ruft das OnUDPRead Event auf. Dort werden die Nachrichten an die entsprechenden Clients-Threads weitergeleitet.
Der Aufruf des OnUDPRead Events erfolgt NICHT in der VCL.
Geprüft durch Abfrage if (MainThreadID <> GetCurrentThreadID) then Die Threads empfangen die Nachrichten und machen damit etwas.
Auf das erfolgt nicht in der VCL.

Ich sage auch nicht, dass es am UDP hängt! Ich bekomme es nur damit nachgestellt. Es hängt definitiv die VCL (siehe IdleEvent). Eventuell ist auch etwas anderes Schuld. Synchronize Aufrufe sind KEINE im Programm.
CPU Auslastung vom MainThread ist laut Prozessexplorer 0.05, während die Anwendung hängt!
Mein Rechner hat 24 Kerne, eine volle Auslastung wären demnach 4%, welche ich aber NICHT habe.

Kleine Korrektur, es ist nicht "WaitForsingleObject" sondern "MsgWaitForMultipleObjects".
Wenn der Returnwert = WAIT_OBJECT_0 ist, wird die Thread-Queue abgearbeitet mit while PeekMessage(MessageData, 0, 0, 0, PM_REMOVE) do Ja, alle Variablen für die Zeitmessung sind lokal. Ich hatte TC2 vergessen mit in dem Codeschnipsel zu schreiben. Ist ja nur ein Ausschnitt des Codes und da hatte ich TC2 übersehen.
Now this is confusing even more,

If you are using OnUDPRead and it is running in background thread context then what this loop suppose to serve ?
Delphi-Quellcode:
while not Terminated do
begin

  //here a signal is sent via WaitForSingleObject and if the timeout occurs (=250ms), the cyclic call below is made
  if WaitForsingleObject(Something, 250, xxxx) = WAIT_OBJECT_0 do
  begin

  end ;

end ;
Where is running ? and it is hugging something and should be removed, yes altogether, remove it.

Just take a step back and look at the big picture and simplify the whole thing, and don't answer my question, and trying to explain to me, and yes, imagine you are trying to explain the whole thing and i am %100 sure you will figure the miss use of over engineering you are doing.

here a simple approach :
OnUDPRead fired, we read, we are in background thread so no synchronization call of any sort is needed, we process and we exit, no looping no waiting for msg or anything inside these events. you need to log something then use a faster approach and don't want on disk or UI updates, use PostMessage and that is it.
Kas
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#9

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

  Alt 21. Mai 2025, 11:14
Ich versuche es nochmal zu erklären.

Threadübersicht:
UDPServer Anzahl 1 = Thread Nummer 1
UDPClient Anzahl 1..35 = Thread Nummer 2..36
Verarbeitungsthread Anzahl 1..35 = Thread Nummer 37..71
weitere Threads, die für andere Funktionen zuständig sind, allerdings den Verarbeitungsthreads 37..71 auch Nachrichten schicken können.

UDPServer gibt die empfangenen Daten an den UDPClient weiter, via PostThreadMessage
UDPClient gibt Daten nach Prüfung und Validierung und anderen Dingen, an den Verarbeitungsthread weiter, via PostThreadMessage

Verabreitungsthread sieht ungefähr so aus:

Delphi-Quellcode:
while not Terminated do
begin

  Return := MsgWaitForMultipleObjects (Handles, HandleBuffer, False, 251, QS_ALLINPUT);

  //case Return do
  //WAIT_OBJECT_0
  //WAIT_OBJECT_0+Handles
  // : begin
  // while PeekMessage(MessageData, 0, 0, 0, PM_REMOVE) do
  // begin
  // Mach irgendwas mit der Nachricht...
  // end;
  // end;
  //WAIT_TIMEOUT
  //end;

  //zyklischer Aufruf
  var sw := TStopwatch.StartNew;
  var TC : DWORD;
  var TC2 : DWORD;
  TC := GetTickCount;

  //Synchronize(MeineFunktion);
  //Queue(Nil, MeineFunktion);
  //ForceQueue(Nil, MeineFunktion);

  t1 := sw.ElapsedMilliseconds;
  //Protokollierung von t1 ...

  TC2 := GetTickCount - TC;
  //Protokollierung von TC2 ...
end ;
Wie gesagt, nur ein grober Auszug...
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
486 Beiträge
 
Delphi 12 Athens
 
#10

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

  Alt 21. Mai 2025, 11:26
Das Verhalten mit dem VCL Hänger scheint genau dann aufzutreten, wenn ich gleichzeitig die Verbindung zu allen 35 UDP Teilnehmern trenne (Netzwerkkabel ziehen oder ähnliches).

UDPClient Anzahl 1..35 = Thread Nummer 2..36

Die Telegramme zu den Clients werden softwareseitig quittiert (da UDP keine Standardmäßige Quittierung hat, ich weiß) und wenn nach einer Zeit X, keine Antwort kommt, wird der Client (=Thread) beendet mit ".Terminate".

Wird das ganze bewusst nur für einen Client (= einen Thread) gemacht mit ".Terminate", passiert an der VCL nichts.
Wird das ganze für 35 gleichzeitig gemacht, dann hängt es.
Soviel habe ich schon rausbekommen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 15:39 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