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
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.
With Qt, I can filter all the QEvent events my application receives or produces with:
qApp.installEventFilter(my_filter_object)
Is there any way to filter Qt signals (of signals and slots) in a similar manner I can filter QEvent events?
With QtCore.QStateMachine.SignalEvent extending QEvent, and StateMachineSignal QEvent.Type being there, everything seems to be in place, but my event filter can't seem to catch one of these.
IOW, is there any way to get the signal's name (index), the signal emitting object, and the passed arguments, for each signal of every QObject in my application without explicitly connecting to it?
Thanks!
No. The only generic API for monitoring signals is QSignalSpy, but that requires an explicit connection to a specific object and signal. The only other thing is the TestLib Framework, which has a command-line option (-vs) that can output all the emitted signals during a test run. But that seems pretty far removed from what you're asking for.
Of course, you can use QMetaObject to list all the signals of a QObject and try to explicitly monitor everything. But that presupposes you can get a reference to all the objects you might be interested in (and that you can actually know in advance what they will be).
The only exception to the above, is for signals that are emitted via a queued connection. These signals, which are most commonly emitted across threads, are wrapped in an event and posted to the event-queue of the receiver's thread. It is possible to detect these kinds of signals by filtering on events of type QEvent.MetaCall.
However, the associated event objects are of type QMetaCallEvent, which is an internal Qt class which is not wrapped by PyQt. Normally, these objects would have id(), sender(), signalId() and args() methods. But in PyQt, all you'll get is a plain QEvent, and thus no information about the emitted signal will be available.
Even if QMetaCallEvent was available, though, the default connection type is not queued - and there is no way to globally reset the default for all signals.
My guess is that the signal events you described are only used for queued connections. In this case events are sent to ensure slots are called after control is passed to the eventloop. Direct connections (wich you would use normally) are essentially just function calls and I doubt there is a way to intercept them without having access to the specific objects.
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
There is an object of class QNetworkReply. There is a slot (in some other object) connected to its finished() signal. Signals are synchronous (the default ones). There is only one thread.
At some moment of time I want to get rid of both of the objects. No more signals or anything from them. I want them gone.
Well, I thought, I'll use
delete obj1; delete obj2;
But can I really?
The specs for ~QObject say:
Deleting a QObject while pending events are waiting to be delivered can cause a crash.
What are the 'pending events'?
Could that mean that while I'm calling my delete, there are already some 'pending events' to be delivered and that they may cause a crash and I cannot really check if there are any?
So let's say I call:
obj1->deleteLater(); obj2->deleteLater();
To be safe.
But, am I really safe? The deleteLater adds an event that will be handled in the main loop when control gets there. Can there be some pending events (signals) for obj1 or obj2 already there, waiting to be handled in the main loop before deleteLater will be handled? That would be very unfortunate. I don't want to write code checking for 'somewhat deleted' status and ignoring the incoming signal in all of my slots.
Deleting QObjects is usually safe (i.e. in normal practice; there might be pathological cases I am not aware of atm), if you follow two basic rules:
Never delete an object in a slot or method that is called directly or indirectly by a (synchronous, connection type "direct") signal from the object to be deleted.
E.g. if you have a class Operation with a signal Operation::finished() and a slot Manager::operationFinished(), you don't want delete the operation object that emitted the signal in that slot. The method emitting the finished() signal might continue accessing "this" after the emit (e.g. accessing a member), and then operate on an invalid "this" pointer.
Likewise, never delete an object in code that is called synchronously from the object's event handler. E.g. don't delete a SomeWidget in its SomeWidget::fooEvent() or in methods/slots you call from there. The event system will continue operating on the already deleted object -> Crash.
Both can be tricky to track down, as the backtraces usually look strange (Like crash while accessing a POD member variable), especially when you have complicated signal/slot chains where a deletion might occur several steps down originally initiated by a signal or event from the object that is deleted.
Such cases are the most common use case for deleteLater(). It makes sure that the current event can be completed before the control returns to the event loop, which then deletes the object. Another, I find often better way is defer the whole action by using a queued connection/QMetaObject::invokeMethod( ..., Qt::QueuedConnection ).
The next two lines of your referred docs says the answer.
From ~QObject,
Deleting a QObject while pending events are waiting to be delivered can cause a crash. You must not delete the QObject directly if it exists in a different thread than the one currently executing. Use deleteLater() instead, which will cause the event loop to delete the object after all pending events have been delivered to it.
It specifically says us to not to delete from other threads. Since you have a single threaded application, it is safe to delete QObject.
Else, if you have to delete it in a multi-threaded environment, use deleteLater() which will delete your QObject once the processing of all the events have been done.
You can find answer to your question reading about one of the Delta Object Rules which states this:
Signal Safe (SS).
It must be safe to
call methods on the object, including
the destructor, from within a slot
being called by one of its signals.
Fragment:
At its core, QObject supports being
deleted while signaling. In order to
take advantage of it you just have to
be sure your object does not try to
access any of its own members after
being deleted. However, most Qt
objects are not written this way, and
there is no requirement for them to be
either. For this reason, it is
recommended that you always call
deleteLater() if you need to delete an
object during one of its signals,
because odds are that ‘delete’ will
just crash the application.
Unfortunately, it is not always clear
when you should use ‘delete’ vs
deleteLater(). That is, it is not
always obvious that a code path has a
signal source. Often, you might have a
block of code that uses ‘delete’ on
some objects that is safe today, but
at some point in the future this same
block of code ends up getting invoked
from a signal source and now suddenly
your application is crashing. The only
general solution to this problem is to
use deleteLater() all the time, even
if at a glance it seems unnecessary.
Generally I regard Delta Object Rules as obligatory read for every Qt developer. It's excellent reading material.
As far as I know, this is mainly an issue if the objects exist in different threads. Or maybe while you are actually processing the signals.
Otherwise deleting a QObject will first disconnect all signals and slots and remove all pending events. As a call to disconnect() would do.
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