Delphi-PRAXiS
Seite 4 von 7   « Erste     234 56     Letzte »    

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 10:52

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

Zitat von AJ_Oldendorf (Beitrag 1548783)
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
Delphi-Quellcode:
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
Delphi-Quellcode:
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.

AJ_Oldendorf 21. Mai 2025 11:14

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
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...

AJ_Oldendorf 21. Mai 2025 11:26

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
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

Kas Ob. 21. Mai 2025 11:30

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

Zitat von AJ_Oldendorf (Beitrag 1548793)
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...

Thank you and well i think we are getting somewhere,
This raise few questions why to mention UDPClient here ? what are their proposes on server side ? if you are responding then use SendTo from the server Binding/Handler to get better idea refer to this example
https://github.com/tinydew4/indy-pro...ServerMain.pas

May be your server doesn't use UDPCLient and this miss understanding on me (translation or something) we get to different problematic approach THE loop
here how to do loop and handle thread messages
https://stackoverflow.com/questions/...ultipleobjects
https://devblogs.microsoft.com/oldne...17-00/?p=36423
Read the question and answers on SO also all the comments there, specially this one
Zitat:

DANGER This is the code that has the bug Raymond wrote about. You need to loop on the peekmessage.

Kas Ob. 21. Mai 2025 11:36

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

Zitat von AJ_Oldendorf (Beitrag 1548795)
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

Great, now explain how these are tied to MainThread, are these are the cause or
Verarbeitungsthread Anzahl 1..35 = Thread Nummer 37..71

Either group causing the main thread to block in waiting state, this behaviour red color on CPU usage unless you are not performing IO operations (reading/writing to disk or network in tight loop) then means one thing, high thread contention and main thread is not couping with it jumping from one place to another and have no time to process Messages.

Capture the culprit, try to exit either group before performing this sudden close, see what is wrong and change that timeout at 250ms to something useful like 30seconds (30000ms), you are not expecting messages that much after all.
Can you disconnect all the clients at once form server ? what happen ? etc...

AJ_Oldendorf 21. Mai 2025 12:17

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

Thank you and well i think we are getting somewhere,
This raise few questions why to mention UDPClient here ? what are their proposes on server side ? if you are responding then use SendTo from the server Binding/Handler to get better idea refer to this example
https://github.com/tinydew4/indy-pro...ServerMain.pas

May be your server doesn't use UDPCLient and this miss understanding on me (translation or something) we get to different problematic approach THE loop
here how to do loop and handle thread messages
https://stackoverflow.com/questions/...ultipleobjects
https://devblogs.microsoft.com/oldne...17-00/?p=36423
Read the question and answers on SO also all the comments there, specially this one

Verstehe das Problem nicht. Ich rufe doch PeekMessage in einer While Schleife auf, so wie in dem verlinkten Beitrag.


Zitat:

Great, now explain how these are tied to MainThread, are these are the cause or
Verarbeitungsthread Anzahl 1..35 = Thread Nummer 37..71

Either group causing the main thread to block in waiting state, this behaviour red color on CPU usage unless you are not performing IO operations (reading/writing to disk or network in tight loop) then means one thing, high thread contention and main thread is not couping with it jumping from one place to another and have no time to process Messages.

Capture the culprit, try to exit either group before performing this sudden close, see what is wrong and change that timeout at 250ms to something useful like 30seconds (30000ms), you are not expecting messages that much after all.
Can you disconnect all the clients at once form server ? what happen ? etc...
Es werden nur die UDPClient-Threads beendet mit Terminate. Die Verarbeitungsthread (Anzahl 1..35 = Thread Nummer 37..71) laufen ganz normal weiter aber bekommen keine Daten von den UDPClient-Threads mehr, da diese beendet wurden. Es gibt allerdings noch andere Threads im Programm, welche den Verarbeitungsthreads weiterhin Daten schicken können, deswegen werden diese auch nicht beendet. Doch, die 250ms brauche ich, da ich eine echtzeitnahe Anwendung betreibe und sehr viele Daten mit den Threads austausche. Bitte keine Diskussion über Echtzeitnah, ich weiß, dass dies unter Windows nicht geht. Darum geht es hier auch nicht.

Ich trenne die UDPClients gleichzeitig! und genau dann tritt das Problem auf.
Trenne ich nur EINEN Client, passiert das Problem NICHT.

Kas Ob. 21. Mai 2025 12:56

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

Zitat von AJ_Oldendorf (Beitrag 1548798)
Es werden nur die UDPClient-Threads beendet mit Terminate. Die Verarbeitungsthread (Anzahl 1..35 = Thread Nummer 37..71) laufen ganz normal weiter aber bekommen keine Daten von den UDPClient-Threads mehr, da diese beendet wurden. Es gibt allerdings noch andere Threads im Programm, welche den Verarbeitungsthreads weiterhin Daten schicken können, deswegen werden diese auch nicht beendet. Doch, die 250ms brauche ich, da ich eine echtzeitnahe Anwendung betreibe und sehr viele Daten mit den Threads austausche. Bitte keine Diskussion über Echtzeitnah, ich weiß, dass dies unter Windows nicht geht. Darum geht es hier auch nicht.

Ich trenne die UDPClients gleichzeitig! und genau dann tritt das Problem auf.
Trenne ich nur EINEN Client, passiert das Problem NICHT.

Still missing the point, what are UDPClient-Threads ?

Are they TThread ?
and more important question
Are you using a UDPClient or TIdUDPClient on server part ?

And more importanter then grammar is When you say 250ms is needed ....... WHYYYYYY

What are those thread suppose to do ? Send and/or receive or processing too ? are you piling jobs on threads and for that you need them to wait for 250ms then do another thing ? that is wrong and contradict the point of using threads to begin with.

When you say you have threads to received on the that event then that event is the one coming form dedicated thread allocated by Indy library to handle you recv and send, then use UDP server to send, and in that event just recv/read and utilize its parameter in that even to send when finished, this can be from any other threads (literally from anywhere).

explain in plain text the logic from receiving a packet to send it, do it on paper and you will find the root of these hugs.

Again refer to https://github.com/tinydew4/indy-pro...ServerMain.pas
Delphi-Quellcode:
procedure TUDPMainForm.UDPServerUDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var
  DataStringStream: TStringStream;
  s: String;
begin
  DataStringStream := TStringStream.Create('');
  try
    DataStringStream.CopyFrom(AData, AData.Size);
    UDPMemo.Lines.Add('Received "' + DataStringStream.DataString + '" from ' + ABinding.PeerIP + ' on port ' + IntToStr(ABinding.PeerPort));
    s := 'Replied from ' + UDPServer.LocalName + ' to "' + DataStringStream.DataString + '"';
    ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, s[1], Length(s));
  finally
    DataStringStream.Free;
  end;
end;
Do send using "ABinding: TIdSocketHandle" "ABinding.SendTo" from anywhere, in other words no dedicated thread, to duck rubber explain it,
having TIdUDPServer on your application/server will remove the need for threads to receive and send, leaving one group of threads, the processing, you want to dedicate one per client ? ok that is fine, now i want you to question the existence of two group of threads, and explain them.

I am sure you miss understanding one functionality somewhere.

Kas Ob. 21. Mai 2025 13:02

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
Receiving from UDP is or can be blocking and can be non blocking, you really don't need to dedicate a thread per identified connection, just recv/read and pass to a thread then write/send from anywhere.

simplify the the groups need and keep only one, also if you like loop like that then wait on call and block on recv then handle then send, loop again, this will even simplify the things further, removing the need to pass data between threads altogether.

Kas Ob. 21. Mai 2025 13:12

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
One more thing to understand, that you might be missing,

UDP is unlike TCP, in case of TCP you can not send without checking the socket is ready to write/send, well you can but it might fail with error and ask you to block or to wait, UDP it is ready always, like always always, just SendTo and call it a day, it might fail or drop the packet but you don't have control about it as there is nothing to do about it, will not explain how to mitigate this here as it is irrelevant your case, 35 clients unless the traffic is saturating you connection it will work like charm.

AJ_Oldendorf 21. Mai 2025 13:25

AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
 
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"


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:12 Uhr.
Seite 4 von 7   « Erste     234 56     Letzte »    

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