6. Qt 信号与信号槽 (7)-QMetaObject:: activate

it2026-09-26  10

最后调用callFunction() 或者metaCall()

void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) { // 这里得到的是QObject的数据,首先判断是否为阻塞设置 if (sender->d_func()->blockSig) return; // 得到全局链表 QConnectionList * const list = ::connectionList(); if (!list) return; QReadLocker locker(&list->lock); void *empty_argv[] = { 0 }; if (qt_signal_spy_callback_set.signal_begin_callback != 0) { locker.unlock(); qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index, argv ? argv : empty_argv); locker.relock(); } // 在sender的哈希表中得到sender的连接 QConnectionList::Hash::const_iterator it = list->sendersHash.find(sender); const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd(); if (it == end) { if (qt_signal_spy_callback_set.signal_end_callback != 0) { locker.unlock(); qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); locker.relock(); } return; } QThread * const currentThread = QThread::currentThread(); const int currentQThreadId = currentThread ? QThreadData::get(currentThread)->id : -1; // 记录sender连接的索引 QVarLengthArray<int> connections; for (; it != end && it.key() == sender; ++it) { connections.append(it.value()); // 打上使用标记,因为可能是放在队列中 list->connections[it.value()].inUse = 1; } for (int i = 0; i < connections.size(); ++i) { const int at = connections.constData()[connections.size() - (i + 1)]; QConnectionList * const list = ::connectionList(); // 得到连接 QConnection &c = list->connections[at]; c.inUse = 0; if (!c.receiver || (c.signal < from_signal_index || c.signal > to_signal_index)) continue; // 判断是否放到队列中 // determine if this connection should be sent immediately or // put into the event queue if ((c.type == Qt::AutoConnection && (currentQThreadId != sender->d_func()->thread || c.receiver->d_func()->thread != sender->d_func()->thread)) || (c.type == Qt::QueuedConnection)) { ::queued_activate(sender, c, argv); continue; } // 为receiver设置当前发送者 const int method = c.method; QObject * const previousSender = c.receiver->d_func()->currentSender; c.receiver->d_func()->currentSender = sender; list->lock.unlock(); if (qt_signal_spy_callback_set.slot_begin_callback != 0) qt_signal_spy_callback_set.slot_begin_callback(c.receiver, method, argv ? argv : empty_argv); #if defined(QT_NO_EXCEPTIONS) c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); #else try { // 调用receiver的方法 c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); } catch (...) { list->lock.lockForRead(); if (c.receiver) c.receiver->d_func()->currentSender = previousSender; throw; } #endif if (qt_signal_spy_callback_set.slot_end_callback != 0) qt_signal_spy_callback_set.slot_end_callback(c.receiver, method); list->lock.lockForRead(); if (c.receiver) c.receiver->d_func()->currentSender = previousSender; } if (qt_signal_spy_callback_set.signal_end_callback != 0) { locker.unlock(); qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index); locker.relock(); } } void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) { int signal_index = signalOffset + local_signal_index; /* 我们所做的第一件事,是快速检查一个 64 位的位蒙版 bit-mask。如果为 0, * 我们就知道没有连接到该信号的东西,可以迅速返回, * 这意味着,发送一个没有与槽连接的信号是相当迅速的。*/ if (!sender->d_func()->isSignalConnected(signal_index)) return; // nothing connected to these signals, and no spy /* ... 跳过调试信息和 QML 调用,以及一些合理性检查 ... */ /* 使用互斥锁,因为 connectionList 中的所有操作都是线程安全的 */ QMutexLocker locker(signalSlotLock(sender)); /* 获取该信号的 ConnectionList。此处做了一些简化。真实的代码还为列表添加了引用计数和一些合理性检查 */ QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists; const QObjectPrivate::ConnectionList *list = &connectionLists->at(signal_index); QObjectPrivate::Connection *c = list->first; if (!c) continue; // 我们需要最后一次检查,确保在信号发出的过程中添加的信号不会在本次发出过程被触发。 QObjectPrivate::Connection *last = list->last; /* 遍历槽 */ do { if (!c->receiver) continue; QObject * const receiver = c->receiver; const bool receiverInSameThread = QThread::currentThreadId() == receiver->d_func()->threadData->threadId; // 确定该连接应该立即发出,还是放入事件队列 if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { /* 从根本上说,就是复制参数,发出事件 */ queued_activate(sender, signal_index, c, argv); continue; } else if (c->connectionType == Qt::BlockingQueuedConnection) { /* ... 跳过 ... */ continue; } /* 助手结构体,设置 sender()(并且在超出作用域之后重新设回 */ 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) { /* ... 跳过 ... Qt5 风格的指向函数指针的连接 */ } else if (callFunction && c->method_offset metaObject()->methodOffset()) { /* 如果存在 callFunction(指向由 moc 生成的 qt_static_metacall 的指针, * 调用该函数。还需要检查已保存的 metodOffset 是否依旧可用 * (因为我们可能在析构函数中调用) */ locker.unlock(); // 实际调用时不能持有锁 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv); locker.relock(); } else { /* 动态对象 */ const int method = method_relative + c->method_offset; locker.unlock(); metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv); locker.relock(); } // 检查该对象是否被槽析构 if (connectionLists->orphaned) break; } while (c != last && (c = c->nextConnectionList) != 0); }
最新回复(0)