How am I blocking the event loop
-
I have written a class that handles a TCP socket connection. I also have a timer (X seconds) that alerts me if a response has not been received in X time over the socket.
When I call a method that sends a message over the socket, the characters go out, and a response comes back almost instantaneous, BUT....my readyRead slot does not run. However, it does run once the above timer expires. It's as if the event loop lost the data received signal...or was blocked some how. But once the timeout signal fires then the readyRead slot runs right after.
Out of interest, I tried calling that same function as a slot (using emit). Then everything works perfectly, and the readyRead signal fires as soon as data is actually received.
Why is this happening (conceptually - no need to ask for code)?? What can cause a signal to get lost, or what could block the event loop (yet an identical method call using emit works fine). I don't use QThreads....pretty simple
-
Ok solved it! I found a couple things including a poorly designed loop (per SGaist) and also sending to the QTcpSocket while in the readyRead slot (leading to receiving data while in the slot) (per JHilk).
The problem was intermittent, but running with Valgrind slowed everything down enough that I was able to confirm the cause(s). Now working properly....
Thanks for the feedback, and interesting discussion on how the slots are handled.
-
Hi,
Got any while loop running ?
-
@SGaist I do have quite a few, but why would they run (indefinitely/in a way that blocks)...but only if I call the method directly instead of using emit?
I can narrow down my investigate of while loops if I could understand how this could happen
-
@ocgltd said in How am I blocking the event loop:
Why is this happening (conceptually - no need to ask for code)??
Then no expectation of addressing your particular problem.
What can cause a signal to get lost,
Not connecting it, or connecting the wrong object, would be the top contenders.
If there are no user threads involved then if the signal is emitted everything connected to it will be executed before the "emit" signal returns. If something in a connected slot causes it it to never return then the program will become non-responsive. If something in a slot is triggering more (the original) signals in a circular arrangement then this might also never return.
-
-
@JonB I have the connection setup as Qt::QueuedConnection, so it's more than just a simple call. It uses the eventloop to call my method.
But...I had a thought.
I send data (and receive data) over the TCP socket while I'm in the QTimer timeout slot. Does Qt implement slot processing in such a way that if a new signal arrives while a slot is running (or signals are being processed), that new signal will only be processed next time the eventloop detects idle or receives a NEW signal?
That would explain my symptom.
-
-
@ocgltd said in How am I blocking the event loop:
I have the connection setup as Qt::QueuedConnection, so it's more than just a simple call
What @JonB means is that "emit" is an empty macro. So "emit signal();" is EXACTLY the same as "signal();".
-
@ocgltd said in How am I blocking the event loop:
@JonB I have the connection setup as Qt::QueuedConnection, so it's more than just a simple call. It uses the eventloop to call my method.
As @jsulm has said on my behalf :), I was talking about
emit signal()
being identical tosignal()
, no more and no less. In your case, either one would queue the signal.Does Qt implement slot processing in such a way that if a new signal arrives while a slot is running (or signals are being processed), that new signal will only be processed next time the event loop detects idle or receives a NEW signal?
For, say, a queued connection signals are only processed (slots called) when the event loop is next hit.
An interesting one would be if the first signal has a queued connection and the new signal a direct connection. In this case I imagine the new signal would be processed immediately, before the previous queued connection was started or even in the middle of it being processed/its slots executing. The default (at least where no threads involved) direct connection effectively means that slots are called directly from the
[emit] signal()
statement, just as though it directly called each slot in turn before continuing to the next statement. So far as I know, the fact that, say, a signal/slot (queued or not) is currently in progress would not be taken into account or alter this behaviour. -
@ocgltd well, yes and probably
As long as you're inside a slot, no other remaining (queued up) events will be processed.
Also if your event processing takes forever, new events won't appended to the currently "todo" list,
new events will be queued up and processed when the event loop is run next
also if you try to write to the socket from the ready read slot that can lead to event loop blocks. I think thats explicitly stated in the documentation?
Edit: only found this in my quick search
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
-
Ok solved it! I found a couple things including a poorly designed loop (per SGaist) and also sending to the QTcpSocket while in the readyRead slot (leading to receiving data while in the slot) (per JHilk).
The problem was intermittent, but running with Valgrind slowed everything down enough that I was able to confirm the cause(s). Now working properly....
Thanks for the feedback, and interesting discussion on how the slots are handled.
-
O ocgltd has marked this topic as solved on