![]() |
Thread.Queue, Zeitmessung, Thread hängt angeblich
Hallo zusammen,
ich habe versucht den Titel auf das nötigste zu reduzieren. Folgender Fall: Ich habe ganz viele Threads, welche früher über Synchronize jeweile eine eigene "zeitaufwändige" Funktion aufgerufen haben. Ich wollte, das die VCL nicht mehr hängt, auf Queue umstellen und habe vor und nach dem Synchronize eine Zeitmessung eingebaut
Delphi-Quellcode:
TC2 ist teilweise 500ms.
TC := GetTickCount;
//Synchronize(MeineFunktion); Queue(Nil, MeineFunktion); TC2 := GetTickCount - TC; //Protokollierung von TC2... Unter Synchronize verstehe ich das ja, aber wieso bei Queue auch? Hat jemand dazu eine Idee? Kann der Thread durch irgendwas "blockiert" sein und wenn ja, wie bekomme ich raus, durch was? Ich hoffe, ihr habt dazu eine Idee |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Kann es denn passieren, dass die gesamte Funktion inkl Zeitmessung auch mal vom Hauptthread direkt ausgeführt wird? In dem Fall entspricht das Queue nämlich einem Synchronize und du könntest stattdessen ForceQueue verwenden. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Nein, der Source oben ist im Execute-Teil des Threads.
Was komisch ist, innerhalb der Funktion "MeineFunktion" habe ich auch eine Zeitmessung, die aber nicht zuschlägt. Das verstehe ich noch nicht wirklich... |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Just use a profiler and it will log the blocking method/function/operation, then track the call stack to get better understand how landed here and what it is waiting for.
I think any profiler will do, for my self and as daily driver i use NQS Method Timer from ![]() In other words wear investigator hat and think outside the box, you did not mention essential stuff like: 1) if the CPU is being used at that moment or not, like a core at full cycle rotating or not 2) Use Process Explorer or Process Hacker and watch the threads tab, what is going there, do you have rouge thread(s) triggering cosmic number of context switches or not 3) Is the UI responsive or not, can you increase the effect to longer period like 10 seconds and see if Windows mark the UI as non responsive, 4) Also important question, do you use Applicatio.ProcessMessages ? 5) Is there silent exceptions 6) What did you described might have similarity when a loop namely While..do or repeat until lost its bound and went full 32bit, but this can be easy to catch with high CPU usage. .... And good luck ! |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Führen code im Hauptthread aus. In windows: Synchronize udn Queue führen den code "sofort" im Hauptthread aus. ForceQueue setzt die Ausführung des Codes ans Ande der MessageQueue und führt den Code aus kurz bevor Application.OnIdle passiert. Ich habe außerdem festgestellt, dass Application.processmessages nicht gut mit Multithreading und Synchronization und warten und blockieren USW. zusammenspielt... also am Besten nie Application.processmessages nutzen. Am besten immer GetTickCount64 benutzen GitTickCount ist deprecated. Bei so kleinen workloads (null workload) vieleicht sogar nen ![]() |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Liste der Anhänge anzeigen (Anzahl: 2)
Hi Kas Ob.,
ich werde mir den Profiler angucken, danke für den Tip. Zu deinen Fragen: 1) Die CPU Auslastung ist die gesamte Zeit <2%. Auch zu dem Zeitpunkt, wo das Problem auftritt. 2) Im Prozess Explorer sieht man zum Zeitpunkt des Problems, dass einige Threads rot markiert werden. Ich denke, dass bedeutet, dass diese Threads hängen. Im Anhang auch 2 Bilder. Einmal vom VCL Thread und einmal von der Anwendung selber (ja es sind verdammt viele Threads, es ist auch eine große Anwendung) 3) Die Oberfläche des Programmes lässt sich wirklich nicht bedienen für ca 4-5s. Das Problem kann ich reproduzieren in meiner Anwendung allerdings dauert es nie länger als 5s. 4) Ich benutze Application.ProcessMessages nicht 5) Es gibt einige Stellen im Programm, wo Exceptions abgefangen und behandelt werden 6) CPU Auslastung ist keine vorhanden Für mich sieht es so aus, dass die besagten Threads in dem Moment keine Rechenzeit erhalten. Eine CPU Auslastung kann ich aber nicht feststellen.
Delphi-Quellcode:
So sieht das ganze grob aus.
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 TC := GetTickCount; //Synchronize(MeineFunktion); Queue(Nil, MeineFunktion); TC2 := GetTickCount - TC; //Protokollierung von TC2... end; Die Funktion "MeineFunktion" sieht etwa so aus:
Delphi-Quellcode:
Verwundert bin ich nur, dass die Protokollierung von TC2 zuschlägt, allerdings von TC4 nicht. (zur Info, die Protokollierung erfolgt nur, wenn der Wert >200ms ist)
procedure MeineFunktion;
begin var TC3 : DWORD; var TC4 : DWORD; TC3 := GetTickCount; //Mache irgendwas zeitaufwändiges TC4 := GetTickCount - TC3; //Protokollierung von TC4... end; |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
auch mit ForceQueue, erfolgt die Protokollierung von TC2 aber innerhalb der Funktion, schlägt keine Protokollierung von TC4 zu. VCL hängt auch.
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 TC := GetTickCount; //Synchronize(MeineFunktion); ForceQueue(Nil, MeineFunktion); TC2 := GetTickCount - TC; //Protokollierung von TC2... end; |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Wo findet das "Protokolieren " statt?
Ist das eine Festplatte? oder eine andere Sequenzielle Systemresource? Vielleicht ein Bereich der durch einen Monitor, eine CS oder eine Mutex geschützt ist? Du musst die Sachen die im Nebenthread passieren woanders protokolieren als die Sachen die im Hauptthread passieren, wenn das Protokoll die Nebenläufigkeit nicht behindern soll. Das ist dir klar oder? Wenn du Nebenläufigkeit haben willst dürfen keine gemeinsamen Variablen oder Resourcen(Festplatte, Systembus, Schnittstelle, Systemhandle) genutzt werden. Es sei denn es ist dir egal wenn alle Threads die diese Resource benutzen jeweils warten bis sie benutztbar ist. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
TL;DR; ?
Ich habe auch schon TStopwatch probiert. Kommt zum gleichen Ergebnis wie GetTickCount. Zum Thema Protokollierung: Die sieht etwa so aus:
Delphi-Quellcode:
Die Protokollierung ist sicherlich nicht das Problem. Die Funktion wird sowohl für die Protokollierung von TC2 als auch TC4 benutzt, natürlich immer mit dem entsprechenden Übergabewert als Value und Aufrufer-String
procedure MyProto(aValue: DWord; aAufrufer : String);
begin if aValue >= 200 then //=200ms begin tmpStr := aAufrufer + ' - Value: ' + aValue.ToString; //Senden des Strings an den Protokoll-Thread, welcher für das Schreiben zuständig ist //PostThreadMessage zum Protokoll-Thread end; end; |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Zitat:
Delphi-Quellcode:
Die sollte dann einen HighResolution Timer nehmen, wenn auf True.
class property IsHighResolution: Boolean read FIsHighResolution;
Ist womöglich weniger anfällig für Hänger, was noch zu beweisen wäre ... :stupid: |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
IsHighResolution ist True.
TStopWatch liefert trotzdem ein ähnliches Ergebnis. Muss ich noch was umstellen bei TStopwatch?
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; //Synchronize(MeineFunktion); //Queue(Nil, MeineFunktion); ForceQueue(Nil, MeineFunktion); t1 := sw.ElapsedMilliseconds; //Protokollierung von t1 ... end; |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Dann hängt der HighResolution Timer wohl genauso.
Könnte es an der Schleife liegen, welche die Queue flutet? Vielleicht versuchtst Du mal die Sequenz einzeln, ohne Schleife aufzurufen und zu messen, oder zu versuchen wie oft der in die Queue läuft. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Für mich sieht es so aus als ob das Protokoll verantwortlich ist. Auch wenn es mit Metacode und Brotkrumen an achtem Code immer etwas schwer zu verstehen ist...
Führe ein Protokoll für den Nebenthread das nur im Speicher geführt wird und im Nebenthread erzeugt wurde. Dann übergebe das Protokoll in OnTerminate aus dem NebenThread in dein eigentliches Protokoll. Nur so kannst du verhindern das ein Thread beim Protokolieren auf den anderen wartet. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
@QuickAndDirty:
Also, die VCL hängt. Wenn ich keine Protokollierung sondern nur ein Breakpoint auf die Abfrage >=200 mache, kommt er auch rein. Ob ich es in ein Protokoll schreibe oder nicht, völlig egal. Es wird außerdem in das Protokoll mit "PostThreadMessage" eine Nachricht geschickt. Das führt nicht zu einem VCL Hänger. Es passiert auch nur unter bestimmten Umständen (ich kann das provozieren). Wenn alles "normal" läuft, geht der Thread auch durch diese Funktion und nichts wird protokolliert. Es ist also kein generelles Problem der Funktion. Deswegen glaube ich immernoch, dass der Thread "blockiert" bzw keine Rechenzeit mehr bekommt. So sieht es für mich irgendwie aus. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Wenn du das provozieren kannst, dann sag doch mal wie. Vielleicht gibt das ja einen Hinweis auf die Ursache.
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
In einem ganz anderen Thread sind ca 35 UDP Teilnehmer mit der Anwendung verbunden und wenn ich ca 10 Teilnehmer (oder auch mehr) die Verbindung trenne, dann passiert es. Aber auch erst zeitverzögert nach einigen Sekunden. Aber der Thread, der anscheinend hängt, hat damit gar nichts zu tun. Daher weiß ich nicht, ob das nur Zufall ist oder irgendwas mit Kontextwechseln zu tun haben könnte.
Ist es denn generell möglich, dass ein Thread, der gerade irgendwo läuft, geblockt wird von außen? Natürlich ohne das dieser Thread auf irgendwas wartet. Also wie in meinem Beispiel unten, while not Terminated Schleife, Synchronize/Queue/ForceQueue und dann wird er "pausiert" und setzt dann aber genau an der Stelle fort? |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Ändert die ThreadPriority irgendetwas? Es ist ja nun schon so, dass realistischer weise von den 200 threads von all den prozessen die laufen nur ein paar wirklich gleichzeitig laufen. Allerdings weiß ich nicht wie genau sich prozess priorität und thread priorität addieren...multiplizieren...? Aber da du eh schon alles ausprobiert hast, warum nicht auch thread priority? Ich frage mich wirklich wie PostThreadMessage die Queue des Threads manipuliert ohne sich mit der MessageLoop des Threads zu synchronisieren. Ich suche ja schon länger nach einer einfachen Lockfree-Queue. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Suspend sollte NIEMALS verwendet werden :!:
(OK, ein Thread sich selbst geht, aber auch da gibt es Besseres, und von außerhalb ist es einfach nur gefährlich, da nicht bestimmt werden kann, ob an aktueller Stelle angehalten werden darf) z.B. es wird grade ein String kopiert oder eine Speicheranforderung (delphis Speichermanager/FastMM) abgearbeitet oder der Code ist grad in einer Sperre (CritticalSection oder so) drin, dann kannst du damit das komplette Programm (andere Threads) blockieren. Andersrum kann ein Thread auch so blockiert werden (ohne ihn selbst anzuhalten) ... z.B. CriticalSections und Dergleichen. Ob jetzt TStopwatch oder GetTickCount ist auch egal. TStopwatch bietet ein paar nette Features und ist genauer. GetTickCount hat auf vielen Systemen standardmäßig eine Auflösung von etwa 16 Millisekunden. (Kürzeres kann nicht gemessen werden und ist immer 0 und längeres wird gerundet) Zitat:
Für den Hauptthread macht es also keinen Unterschied, außer dass beim Queue die Funktion nicht sofort, sondern erst später ausgeführt wird. (Ausnahme, das Queue wird innerhalb des Hauptthreads ausgeführt, dann macht der Schrott nicht das, wonach es klingt, sondern führt es sofort aus, genauso wie beim Synchronize) Bugfix: einfach immer ForceQueue statt Queue verwenden, das ist wirklich immer verzögert. Ausnahme, der Hauptthread wartet auf diesen Thread (WaitFor oder sonstwas) oder auf etwas Anderes und der Thread will ein Synchronize machen, wodurch er auf den Hautthread wartet (bis jener diese Funktion fertig ausgeführt hat), aber da der Hauptthread wartet, kommt er nicht dazu das zu machen und beide warten bis in alle Ewigkeit. Beim Queue ist die Zeitmessung aber auch bissl nutzlos, da es dort nur das Eintragen in die Liste misst, aber nicht die Funktion. Wenn, dann innerhalb der Funktion messen. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Zitat:
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
There is good advices above, and here what i see
1) according to screenshot, your main thread is spending in kernel time 4 times more than user time, that way more than usual or accepted and this is the cause. 2) saying you see red in CPU usage, meaning the threads are spedning too much time and also invoking system calls (not system functions), and/or too much IO operations. 3) This bring me to ask how many Threads are you creating and destroying per second ? 4) How many IO operation are you issueing per second ? 5) you mentioned UDP above, i might missed something, but if this is server, are you polling the status like that code above? i mean perform select over 250ms then loop back ? how many threads are doing this? 6) I have problem with this "if WaitForsingleObject(Something, 250, xxxx) = WAIT_OBJECT_0 do" in what thread it being used, also one thread or more? like 64 ? 7) Are these TC1,TC2,TC3,TCx... local variables ? i mean all, or some of them are accessible and writable by multiple thread, when i see stuff like this "TC2 := GetTickCount - TC;" this should not be used out side the scope of this thread, example how this can go wrong, two threads calling GetTickCount each within interval supposed to be 250ms, you assume the difference between their result will be within 250ms, in real life the difference can be 5 seconds (5000ms)! or even more, you have no control over this. 8) also as (7) and even more important if one thread performed an action and in the last stage updated some checkpoint timer lets say grabbed GetTickCount, then signaled for finish, if you are signaling before grabbing the time, then this thread might block for more time the next, then update the time indicator send the next thread in waiting state because code like this "TC2 := GetTickCount - TC;" if TC is not local and only limited to this thread then it easily can be negative value, be extra careful here. Now to most important quesitons, what are the operations these threads are doing ? writing files or sending/recv packets ? and why there is this very short period 250ms anywhere in your code ? this is not a joke and easily can go from speed enhancer to speed killer. no matter what is the operation, then you must remove the dependency on time and switch to operation completion, in other words the fact you depend on GetTickCount to time or singal your threads to work, indicate critical problem in and design shortcoming. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Einzig mir bekannte Ausnahme ist eben, wenn Queue aus dem Hauptthread aufgerufen wird, wodurch es fast wie Synchronize wirkt (die Funktion wird direkt aufgerufen, ohne in der Queue zu landen). Oder wenn jemand es geschafft hat den Speicher zu schrotten (BufferOverflow, mistige Zeiger und Dergleichen), aber dann hat man eh andere Probleme, als nur dieses Hängen. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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:
Die Protokollierung der Zeitmessung sowohl von t1 als auch TC2, schlägt zu. Egal welcher der 3 Aufrufe genutzt wird.
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; Eine Prüfung vorher auf
Delphi-Quellcode:
zeigt auch, dass es nicht der VCL Thread ist als Aufrufer.
if (MainThreadID <> GetCurrentThreadID) then
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? |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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 |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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? |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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:
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.
//Synchronize(MeineFunktion);
//Queue(Nil, MeineFunktion); //ForceQueue(Nil, MeineFunktion); 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:
never together, well you can, but nothing good is coming out of it.
//Synchronize(MeineFunktion);
//Queue(Nil, MeineFunktion); //ForceQueue(Nil, MeineFunktion); 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, ![]() 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 ? |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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:
Die Threads empfangen die Nachrichten und machen damit etwas.
if (MainThreadID <> GetCurrentThreadID) then
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:
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.
while PeekMessage(MessageData, 0, 0, 0, PM_REMOVE) do
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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) |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
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 |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
If you are using OnUDPRead and it is running in background thread context then what this loop suppose to serve ?
Delphi-Quellcode:
Where is running ? and it is hugging something and should be removed, yes altogether, remove it.
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 ; 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. |
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:
Wie gesagt, nur ein grober Auszug...
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 ; |
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 |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
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 ![]() 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 ![]() ![]() Read the question and answers on SO also all the comments there, specially this one Zitat:
|
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
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... |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
Verstehe das Problem nicht. Ich rufe doch PeekMessage in einer While Schleife auf, so wie in dem verlinkten Beitrag. Zitat:
Ich trenne die UDPClients gleichzeitig! und genau dann tritt das Problem auf. Trenne ich nur EINEN Client, passiert das Problem NICHT. |
AW: Thread.Queue, Zeitmessung, Thread hängt angeblich
Zitat:
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 ![]()
Delphi-Quellcode:
Do send using "ABinding: TIdSocketHandle" "ABinding.SendTo" from anywhere, in other words no dedicated thread, to duck rubber explain it,
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; 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. |
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. |
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. |
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 10:15 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