I am developing a consequent program which is very sensitive to time (based on delayed video streams), and since I'm not sure about how the signals and slots are implemented within Qt, I don't know when they are executed. Are they really executed in real time like callbacks would do, or are they processed before the next iteration of some kind of main loop?
My question would be about timers in particular: when a timer times out (which must be another thread), does it connect to the signal "instantaneously" (next instruction for example) nearly like an interrupt would do, or does it wait for the end of some loop?
Thanks for your insight,
Regards,
Mister Mystère
The last argument of QObject::connect is the connection type, which determines when slot will be executed. From the documentation:
Qt::AutoConnection - If the signal is emitted from a different thread than the receiving object, the signal is queued, behaving as
Qt::QueuedConnection. Otherwise, the slot is invoked directly,
behaving as Qt::DirectConnection. The type of connection is determined
when the signal is emitted.
Qt::DirectConnection - The slot is invoked immediately, when the signal is emitted.
Qt::QueuedConnection - The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in
the receiver's thread.
Qt::BlockingQueuedConnection - Same as QueuedConnection, except the current thread blocks until the slot returns. This connection type
should only be used where the emitter and receiver are in different
threads.
http://woboq.com/blog/how-qt-signals-slots-work.html
This seems to be quite a good description, though I haven't read it in detail.
Main point: there's direct connections and deferred connections. Direct connections are executed immediately.
You can be quite sure the timer is not implemented in a different thread but instead is handled inside the event loop. Which means that when the timer fires, it is instantly connected. However the granularity for the timer to fire is your main problem.
If your timer were to emit the signal in a different thread, the slot would be called in the thread the receiving object belongs to. Which means that it would be deferred to the event loop. (As you can see it would not help to have the timer operate in a thread of its own.)
And additionally in Qt5 you can set QTimer's precision: Qt::TimerType
Related
I'm dealing with an application where many signals get fired after which a reconnect follows. I'll explain in detail how the application works, and also where my confusion starts.
1. Reconnecting a signal
In my application, I reconnect signals frequently. I will use the following static function for that, taken from the answer of #ekhumoro (and slightly modified) from this post: PyQt Widget connect() and disconnect()
def reconnect(signal, newhandler):
while True:
try:
signal.disconnect()
except TypeError:
break
if newhandler is not None:
signal.connect(newhandler)
2. The application
Imagine the function emitterFunc(self) looping through a list of objects. Upon each iteration, the function connects mySignal to an object, fires the signal and then disconnects mySignal again at the start of the next iteration step. The fired signal also carries some payload, for example an object Foo().
EDIT:
The design shown above is simplified a lot. In the final design, the signal emitter and the receiving slot might operate in different threads.
For reasons that would lead us too far astray, I cannot just connect all the objects at once, emit a signal, and finally disconnect them all. I have to cycle through them one-by-one, doing a connect-emit-disconnect procedure.
Again for reasons that would lead us too far, I cannot just call these slots directly.
3. A mental image of the Signal-Slot mechanism
Over time, I have built up a mental image of how the Signal-Slot mechanism works. I imagine a Signal-Slot engine absorbing all fired signals and putting them in a Queue. Each signal awaits its turn. When time is ready, the engine passes the given signal to the appropriate handler. To do that correctly, the engine has some 'bookkeeping' work to ensure each signal ends up in the right slot.
4. Behavior of the Signal-Slot engine
Imagine we're at the nth iteration step. We connect self.mySignal to object_n. Then we fire the signal with its payload. Almost immediately after doing that, we break the connection and establish a new connection to object_n+1. At the moment we break the connection, the fired signal probably didn't do its job yet. I can imagine three possible behaviors of the Signal-Slot engine:
[OPTION 1] The engine notices that the connection is broken, and discards sig_n from its Queue.
[OPTION 2] The engine notices that the connection is re-established to another handler, and sends sig_n to the handler of object_n+1 (as soon as it gets to the front of the Queue).
[OPTION 3] The engine doesn't change anything for sig_n. When fired, it was intended for the handler of object_n, and that's where it will end up.
5. My questions
My first question is pretty obvious by now. What is the correct Signal-Slot engine behavior? I hope it is the third option.
As a second question, I'd like to know to what extent the given mental image is correct. For example, can I rely on the signals getting out of the Queue in order? This question is less important - it's certainly not vital to my application.
The third question has to do with time efficiency. Is reconnecting to another handler time-consuming? Once I know the answer to the first question, I will proceed building the application and I could measure the reconnection time myself. So this question is not so vital. But if you know the answer anyway, please share :-)
I would start with your second question, to say that your mental image is partially correct, because a queue is involved, but not always. When a signal is emitted, there are three possible ways of calling the connected slot(s) and two of them use the event queue (a QMetaCallEvent is instantiated on the fly and posted with QCoreApplication's method postEvent, where the event target is the slot holder, or the signal receiver, if you prefer). The third case is a direct call, so emitting the signal is just like calling the slot, and nothing get queued.
Now to the first question: in any case, when the signal is emitted, a list of connections (belonging to the signal emitter) is traversed and slots are called one after the other using one of the three methods hinted above. Whenever a connection is made, or broken, the list will be updated, but this necessarily happens before or after the signal is emitted. In short: there is very little chances to succeed in blocking a call to a connected slot after the signal has been emitted, at least not breaking the connection with disconnect(). So I would mark the [OPTION 3] as correct.
If you want to dig further, start from the ConnectionType enum documentation where the three fundamental types of connection (direct, queued and blocking-queued) are well explained. A connection type can be specified as a fifth argument to QObject's method connect, but, as you'll learn from the above linked docs, very often is Qt itself to choose the connection type that best suits the situation. Spoiler: threads are involved :)
About the third question: I have no benchmark tests at hand to show, so I will give a so called primarily opinion based answer, the kind of answer that starts with IMHO. I think that the signal/slot realm is one of those where the keep-it-simple rules do rule, and your reconnect pattern seems to make things much complicated than they need to be. As I hinted above, when a connection is made, a connection object is appended to a list. When the signal is emitted, all the connected slots will be called somehow, one after the other. So, instead of disconnect/reconnect/emit at each cycle in your loop, why don't just connect all items first, then emit the signal, then disconnect them all?
I hope my (long and maybe tldr) answer helped. Good read.
What happens if I start a QTimer firing at regular intervals but the slot reacting to the timeout signal blocks the main loop for longer than another timer interval. Will the timout signals then be stacked on the Qt main event loop and processed one after another as soon as the event loop runs again?
If yes, what happens if multiple timeout events are stacked on the event queue but the timer is deactivated before they can be processed?
If QTimer object and the signal receiver belong to one thread, no queuing happens. timeout() signal will not (and cannot) be sent again until control flow goes to the event loop, and that won't happen until the slot is completely executed (unless QApplication::processEvents is called in the slot, which can turn this into a mess). But if your slot was being executed longer than the timer's interval, timeout() will be sent once the event loop is free, so your slot will be immedately called again. But QTimer will not send two timeout() signals closer than its interval.
If QTimer is in another thread, and that thread is not busy with something else, it will send timeout() signals regularly regardless of how well slot in another thread goes. This is where Qt's signal-slot system comes in. And it will queue emitted signals. If your slot is slow, it will call it multiple times without delay. If you stop the timer, it won't undo already sent signals and the slot may be called multiple times after it. Additionally, if you stop the timer, there is always a possibility that another signal is being sent just in this moment and your slot will be called once again.
If you want strict intervals between slot invocations regardless of the slot's executing time, you should use single-shot timers. At the end of your slot, start a single-shot timer. When it's timed out, it will invoke your slot and deactivate, so you can start it again at the end of the slot.
If your program's logic depends on the timer's state, you should check that the timer is active at the start of your slot. It's not guaranteed that the timer is active when the slot is being executed.
I discovered quite by accident that instead of the normal style of emitting a signal previously connected to a slot, another way to trigger the slot is:
emit(slotname());
I like that I can skip the step of creating a signal and connecting, but does this REALLY cause the slot to be handled through the event queue? Or is this just calling the slot method directly?
No. emit(slotname()) equals to (slotname()), which merely calls slotname() directly without queue. And it won't automagically call other slots connected to the signal.
emit is actually a macro that evaluates to nothing. It's just a syntactic sugar to show that the code is emitting a signal. Thus the following line
emit nameChanged()
is equivalent to
nameChanged()
It's nothing special, you are actually calling the nameChanged() signal method. The difference is that you don't implement the signal method yourself. You leave Qt's moc to generate the implementation. The generated implementation will call all connected slots, directly or through queue depending on how connections were made and the executing thread.
Therefore, emit(slotname()) defeats the purpose and confuses code readers.
If you are curious, emit is defined in QtCore\qobjectdefs.h:
# define emit
I always use QObject::connect() in all my applications but it is not clear to me its effect when my program is currently inside a function. Suppose I have the following code:
void main() {
//other stuffs here
QObject::connect(xxx,SIGNAL(yyy()),this,SLOT(zzz());
}
void aFunction()
{
//a bunch of codes here
//i am here when suddenly signal is emitted from QObject::connect();
//another bunch of codes here
}
I assume that when the signal is emitted, QObject::connect leaves the function "aFunction()" to execute "zzz()". What will happen to the remaining codes in the "aFunction()"
Thanks.
I can understand the confusion, coming from procedural to event based programming gives me same experience like you do now.
Short answer:
in non multi threaded environment, slot zzz() will be executed after aFunction() finishes. In fact, the signal probably gets emitted after aFunction finishes.
in multi threaded env., same thing but it is "after some time", not after.
Key to understanding this is Event Loop. QApplication::exec() runs a forever loop polling for event. New event is then handled, signals get emitted and depending on the fifth argument of QObject::connect which is a Qt::ConnectionType, ultimately runs the connected slot. You can read QObject documentation for more detail..
So your aFunction probably gets called after some signal, so after it is finished, it's back to event loop again, then your 'suddenly emitted' signal actually gets emitted and zzz is executed.
Even in multi threading environment, inter thread signals and slots work with Qt::QueuedConnection which basically just posts the emitted signal to corresponding thread so that when that thread's event loop come around to process it - it will be executed sequentially as well.
Ultimately what you will have to remember is that this Turing Machine called computers is executing sequences of codes, whether it's semi paralel (e.g time sharing, pipelining) or truly paralel (e.g multi cores, multi cpu) the part where codes get sent (or distributed? or fetched?) to its execution will always run in sequences or in one or more ways have to be simulated to be sequential so that no code is executed twice in multiple execution node.
There is no "suddenly"
I am new to QT. I have created object class QNetworkAccessManager main window as parent. Also registered to SIGNAL finished. It is working fine.
But I want to know in which thread it will run. Will it block the main thread. If i need to perform sequence of get operation how should I need to write the code.
Please give me some sample to understand concept properly.
It certainly does not run in the main thread, the calls to get() are asynchronous.
For example this would keep firing get requests:
while (condition) {
QNetworkRequest request;
request.setUrl(QUrl(m_ServerURL);
m_httpGetUpdatedFile->get(request);
}
You then have the slot for the finished signal which is processing the QNetworkReply. That slot basically should be getting called for each get request you make (even if it fails). If you need to keep track of when all your get requests have finished, you need to keep a track of how many you posted and then have your own finished flag or signal.
QNAM does use threads in the background, but this is completely invisible for your application code. Everything you see will run in the main thread.
QNAM works in the usual Qt way, it will emit signals when things happen, and you connect these signals to slots in your own code, which do things as much as they can. If they don't for example have enough data, then your slots must not block to wait for new data, instead they must return. And then they will be called again when/if there's more data (or you'll get another signal if for example connection was terminated).
Some links, in case you have not read these:
Qt signal & slot documentation
Qt networking documentation