
Originally Posted by
DanH
Likely the signial in the same thread will be executed immediately, while the one in the different thread will be queued. But it could be that they both end up being queued.
Don't guess. If you don't know, rely on what someone else is saying or check in the source code. The signal (the method declared in the "signals" section) is executed only once. There can be zero or more slots connected to the signal and each of them will be executed when the right time comes. What you say wouldn't make sense if you had a signal connected to two slots living in different threads. How would the signal be emitted then? Would it be stalled until both threads were in their event loops at the same time? What if one of the threads wasn't running a loop at all?
There is a terminology problem here.
It is not, if you write what you have written above. And if a question is asked about which signals are deferred and which are emitted immediately. The question was about delays related to timers and networking operations (and other asynchronous operations) and not about slot execution and regardless of what lives in which thread. Networking signals (apart those signalling errors) will always be deferred despite the fact the internal connections are made within the same thread. The same goes with QtConcurrent signals, for instance.
There are four entities to consider: The emit, the slot, the connection, and the "signal", which is essentially a message. It is the delivery of this message to a slot which constitutes "executing" the signal.
No. You can invoke the slot without even having the signal by calling QMetaObject::invokeMethod() and it accepts an argument telling how the slot should be invoked (as a direct or queued connection albeit there is no connection there at all) and processing is exactly the same as with a signal, you also end up with the same QMetaObject::metacall() call.
If something is queued, it is the signal.
You are guessing again. And missing. The signal is emitted and when the slot is in another thread, it is transformed into an event and put in the event loop of the destination thread. When the thread processes its events, the data will be marshalled based on the event and the slot will be called. Look at the source code generated by the moc for a signal, it looks essentially like this:
// SIGNAL 0
void CMSMessageListener::messageReceived(CMSMessage _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
}
// SIGNAL 0
void CMSMessageListener::messageReceived(CMSMessage _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
To copy to clipboard, switch view to plain text mode
There is no check for threads here, the signal is activated immediately. Then activate() loops through the list of connections and either queues the metacall event or executes the slot immediately.
void **argv){
// ...
do {
QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
// ...
do {
// ...
QObject * const receiver
= c
->receiver;
// ...
if ((c->connectionType == Qt::AutoConnection
&& (currentThreadData != sender->d_func()->threadData
|| receiver->d_func()->threadData != sender->d_func()->threadData))
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
continue;
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
continue;
}
const int method = c->method;
// ...
metacall
(receiver,
QMetaObject::InvokeMetaMethod, method, argv ? argv
: empty_argv
);
} while (...);
// ...
} while (...);
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv){
// ...
do {
QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;
// ...
do {
// ...
QObject * const receiver = c->receiver;
// ...
if ((c->connectionType == Qt::AutoConnection
&& (currentThreadData != sender->d_func()->threadData
|| receiver->d_func()->threadData != sender->d_func()->threadData))
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
continue;
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
continue;
}
const int method = c->method;
// ...
metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
} while (...);
// ...
} while (...);
To copy to clipboard, switch view to plain text mode
If something is queued, it is the signal.
To be precise it is a QMetaCallEvent that is queued. And considering the fact that if you have two connections to the same ("alien") thread you'll be getting two such events then I'd lean towards saying that it is the slot invokation that is being queued (especially that the event carries the slot id).
Bookmarks