Qt的訊號與槽的工作機制
阿新 • • 發佈:2019-02-03
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv) { activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv); /* We just forward to the next function here. We pass the signal offset of * the meta object rather than the QMetaObject itself * It is split into two functions because QML internals will call the later. */ } void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) { int signal_index = signalOffset + local_signal_index; /* The first thing we do is quickly check a bit-mask of 64 bits. If it is 0, * we are sure there is nothing connected to this signal, and we can return * quickly, which means emitting a signal connected to no slot is extremely * fast. */ if (!sender->d_func()->isSignalConnected(signal_index)) return; // nothing connected to these signals, and no spy /* ... Skipped some debugging and QML hooks, and some sanity check ... */ /* We lock a mutex because all operations in the connectionLists are thread safe */ QMutexLocker locker(signalSlotLock(sender)); /* Get the ConnectionList for this signal. I simplified a bit here. The real code * also refcount the list and do sanity checks */ QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; const QObjectPrivate::ConnectionList *list = &connectionLists->at(signal_index); QObjectPrivate::Connection *c = list->first; if (!c) continue; // We need to check against last here to ensure that signals added // during the signal emission are not emitted in this emission. QObjectPrivate::Connection *last = list->last; /* Now iterates, for each slot */ do { if (!c->receiver) continue; QObject * const receiver = c->receiver; const bool receiverInSameThread = QThread::currentThreadId() == receiver->d_func()->threadData->threadId; // determine if this connection should be sent immediately or // put into the event queue if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { /* Will basically copy the argument and post an event */ queued_activate(sender, signal_index, c, argv); continue; } else if (c->connectionType == Qt::BlockingQueuedConnection) { /* ... Skipped ... */ continue; } /* Helper struct that sets the sender() (and reset it backs when it * goes out of scope */ QConnectionSenderSwitcher sw; if (receiverInSameThread) sw.switchSender(receiver, sender, signal_index); const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction; const int method_relative = c->method_relative; if (c->isSlotObject) { /* ... Skipped.... Qt5-style connection to function pointer */ } else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { /* If we have a callFunction (a pointer to the qt_static_metacall * generated by moc) we will call it. We also need to check the * saved metodOffset is still valid (we could be called from the * destructor) */ locker.unlock(); // We must not keep the lock while calling use code callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv); locker.relock(); } else { /* Fallback for dynamic objects */ const int method = method_relative + c->method_offset; locker.unlock(); metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv); locker.relock(); } // Check if the object was not deleted by the slot if (connectionLists->orphaned) break; } while (c != last && (c = c->nextConnectionList) != 0); }