> 文章列表 > Qt源码阅读(一) 信号槽的连接与调用

Qt源码阅读(一) 信号槽的连接与调用

Qt源码阅读(一) 信号槽的连接与调用

信号槽连接

文章目录

  • 信号槽连接
    • 信号的连接
      • connect
      • QObject::connectImpl
        • 完整源码
        • 具体分析
      • QObjectPrivate::connectImpl
        • 完整源码
        • 具体分析
    • 槽的调用
      • QMetaObject::activate
      • doActivate
        • 完整源码
        • 具体分析
      • queued_activate
    • 结束

信号槽的连接,其实内部本质还是一个回调函数,主要是维护了信号发送Object的元对象里一个连接的列表。调用connect函数时,将槽的一系列信息,封装成一个Connection,在发送信号时,通过这个列表,去回调槽函数。

信号的连接

下面列举一种信号的连接方式,来大致讲解一下信号的连接过程。

connect

//Connect a signal to a pointer to qobject member function// QtPrivate::FunctionPointer<Func1>::Object返回发送信号的对象类型template <typename Func1, typename Func2>static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,Qt::ConnectionType type = Qt::AutoConnection){typedef QtPrivate::FunctionPointer<Func1> SignalType;typedef QtPrivate::FunctionPointer<Func2> SlotType;Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,"No Q_OBJECT in the class with the signal");//compilation error if the arguments does not match.// 检查信号和槽参数是否一致Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),"The slot requires more arguments than the signal provides.");// 检查信号和槽参数是否兼容Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),"Signal and slot arguments are not compatible.");// 检查信号和槽的返回值是否兼容Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),"Return type of the slot is not compatible with the return type of the signal.");const int *types = nullptr;// SignalType -> QtPrivate::FunctionPointer<Func1>// QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types() 返回信号参数的值对应的元类型id列表if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();return connectImpl(sender, reinterpret_cast<void **>(&signal),receiver, reinterpret_cast<void **>(&slot),new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,typename SignalType::ReturnType>(slot),type, types, &SignalType::Object::staticMetaObject);}
  1. 基本的信号连接的判断,主要是:

    • 信号和槽的参数数量
    • 信号和槽的参数是否兼容
    • 信号和槽的返回值是否兼容
  2. 获取信号参数所对应的元类型Id,

QObject::connectImpl

再就到了一个信号连接的具体内部实现中

完整源码

QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,const QObject *receiver, void **slot,QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,const int *types, const QMetaObject *senderMetaObject)
{if (!signal) {qWarning("QObject::connect: invalid nullptr parameter");if (slotObj)slotObj->destroyIfLastRef();return QMetaObject::Connection();}int signal_index = -1;void *args[] = { &signal_index, signal };// 根据调用来判断是否存在信号,如果当前类没有就去父类中寻找// 直到找到信号或者是最基层的类// 找到信号的index和信号的对象for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)break;}if (!senderMetaObject) {qWarning("QObject::connect: signal not found in %s", sender->metaObject()->className());slotObj->destroyIfLastRef();return QMetaObject::Connection(nullptr);}// 信号下标signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
}

具体分析

同样,我们对这个函数进行分析,

  1. 信号发送者是否为空指针的一个判断

    if (!signal) {qWarning("QObject::connect: invalid nullptr parameter");if (slotObj)slotObj->destroyIfLastRef();return QMetaObject::Connection();
    }
    
  2. 找到信号发送者(sender)的元对象类型(Meta Object)以及信号在对象信号中的位置。如果当前对象没有该信号,就去其父类对象去找。

    for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)break;
    }
    

QObjectPrivate::connectImpl

进一步分析其内部实现:

完整源码

QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,const QObject *receiver, void **slot,QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,const int *types, const QMetaObject *senderMetaObject)
{// 发送对象、接收对象、槽函数对象、信号发送的元对象都不为空 2023-3-11if (!sender || !receiver || !slotObj || !senderMetaObject) {// 任意一个为空,报错且清理空间,并返回const char *senderString = sender ? sender->metaObject()->className(): senderMetaObject ? senderMetaObject->className(): "Unknown";const char *receiverString = receiver ? receiver->metaObject()->className(): "Unknown";qWarning("QObject::connect(%s, %s): invalid nullptr parameter", senderString, receiverString);if (slotObj)slotObj->destroyIfLastRef();return QMetaObject::Connection();}// 去掉const的发送和接受对象QObject *s = const_cast<QObject *>(sender);QObject *r = const_cast<QObject *>(receiver);// 顺序锁,按照顺序依次去对mutex去上锁// 这里依次对发送和接收者的信号去上锁QOrderedMutexLocker locker(signalSlotLock(sender),signalSlotLock(receiver));if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {// ObjectPrivate::get(s) 获取s对应的d指针// connections 维护了所有的信号槽连接QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();if (connections->signalVectorCount() > signal_index) {// 获取信号的连接const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();// 循环遍历while (c2) {// 如果已经存在信号和槽的连接,且为uniqueConnection,则返回if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {slotObj->destroyIfLastRef();return QMetaObject::Connection();}c2 = c2->nextConnectionList.loadRelaxed();}}// 将type与UniqueConnection进行异或,去掉UniqueConnectiontype = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);}// 创建一个新的连接std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};c->sender = s;c->signal_index = signal_index;QThreadData *td = r->d_func()->threadData;td->ref();c->receiverThreadData.storeRelaxed(td);c->receiver.storeRelaxed(r);c->slotObj = slotObj;c->connectionType = type;c->isSlotObject = true;if (types) {c->argumentTypes.storeRelaxed(types);c->ownArgumentTypes = false;}// 将新创建的连接加到连接列表中QObjectPrivate::get(s)->addConnection(signal_index, c.get());QMetaObject::Connection ret(c.release());locker.unlock();QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);Q_ASSERT(method.isValid());s->connectNotify(method);return ret;
}

具体分析

  1. 对一些个空值的判断

    	// 发送对象、接收对象、槽函数对象、信号发送的元对象都不为空 2023-3-11if (!sender || !receiver || !slotObj || !senderMetaObject) {// 任意一个为空,报错且清理空间,并返回const char *senderString = sender ? sender->metaObject()->className(): senderMetaObject ? senderMetaObject->className(): "Unknown";const char *receiverString = receiver ? receiver->metaObject()->className(): "Unknown";qWarning("QObject::connect(%s, %s): invalid nullptr parameter", senderString, receiverString);if (slotObj)slotObj->destroyIfLastRef();return QMetaObject::Connection();}
    
  2. 一个if判断,主要是对Qt::UniqueConnection连接的一些处理,获取当前对象的信号连接列表,并判断当前要连接的信号和槽,之前有没有被连接过,如果有过连接,就直接返回。

    if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {// ObjectPrivate::get(s) 获取s对应的d指针// connections 维护了所有的信号槽连接QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();if (connections->signalVectorCount() > signal_index) {// 获取信号的连接const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();// 循环遍历while (c2) {// 如果已经存在信号和槽的连接,且为uniqueConnection,则返回if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {slotObj->destroyIfLastRef();return QMetaObject::Connection();}c2 = c2->nextConnectionList.loadRelaxed();}}// 将type与UniqueConnection进行异或,去掉UniqueConnectiontype = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);}
    
  3. 创建一个Connection并将连接的信息以及信号的参数设置进去,然后保存到对象的信号连接容器里。

    // 创建一个新的连接std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};c->sender = s;c->signal_index = signal_index;QThreadData *td = r->d_func()->threadData;td->ref();c->receiverThreadData.storeRelaxed(td);c->receiver.storeRelaxed(r);c->slotObj = slotObj;c->connectionType = type;c->isSlotObject = true;if (types) {c->argumentTypes.storeRelaxed(types);c->ownArgumentTypes = false;}// 将新创建的连接加到连接列表中QObjectPrivate::get(s)->addConnection(signal_index, c.get());QMetaObject::Connection ret(c.release());locker.unlock();QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);Q_ASSERT(method.isValid());s->connectNotify(method);return ret;
    

槽的调用

定义一个信号,使用moc生成moc文件之后,我们可以看到信号函数的定义如下:

// SIGNAL 0
void MainWindow::sgnTestFor()
{QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

我们发射一个信号的时候,我们会这样写:

emit sgnTestFor();

我们可以看关于emit的定义:
Qt源码阅读(一) 信号槽的连接与调用

其实emit关键字什么都没有做,只是标识了一下当前发射了信号。所以本质上,发射一个信号实际上就是直接调用了这个信号的函数,也就是调用了QMetaObject中的activate函数。

QMetaObject::activate

函数如下:

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,void **argv)
{int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))doActivate<true>(sender, signal_index, argv);elsedoActivate<false>(sender, signal_index, argv);
}

doActivate

上面的qt_signal_spy_callback_set暂时不清楚是什么玩意,所以我们不管,直接看具体的doActive函数

完整源码

template <bool callbacks_enabled>
void doActivate(QObject *sender, int signal_index, void **argv)
{// 首先获取QObject的private对象QObjectPrivate *sp = QObjectPrivate::get(sender);// 判断信号是否阻塞if (sp->blockSig)return;Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);if (sp->isDeclarativeSignalConnected(signal_index)&& QAbstractDeclarativeData::signalEmitted) {Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,signal_index, argv);}const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;void *empty_argv[] = { nullptr };if (!argv)argv = empty_argv;if (!sp->maybeSignalConnected(signal_index)) {// The possible declarative connection is done, and nothing else is connectedif (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)signal_spy_set->signal_begin_callback(sender, signal_index, argv);if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)signal_spy_set->signal_end_callback(sender, signal_index);return;}if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)signal_spy_set->signal_begin_callback(sender, signal_index, argv);bool senderDeleted = false;{Q_ASSERT(sp->connections.loadAcquire());QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();// 信号连接列表,因为一个信号可能连接了多个槽	const QObjectPrivate::ConnectionList *list;if (signal_index < signalVector->count())list = &signalVector->at(signal_index);elselist = &signalVector->at(-1);// 判断当前线程是不是信号发送者的线程Qt::HANDLE currentThreadId = QThread::currentThreadId();bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();// // We need to check against the highest connection id to ensure that signals added// during the signal emission are not emitted in this emission.uint highestConnectionId = connections->currentConnectionId.loadRelaxed();// 此处也就代表着,一个信号连接的多个槽函数,或者多个连接,会以连接的顺序被触发do {QObjectPrivate::Connection *c = list->first.loadRelaxed();if (!c)continue;do {QObject * const receiver = c->receiver.loadRelaxed();if (!receiver)continue;QThreadData *td = c->receiverThreadData.loadRelaxed();if (!td)continue;bool receiverInSameThread;// 判断发送和接受是不是同一个线程if (inSenderThread) {receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();} else {// need to lock before reading the threadId, because moveToThread() could interfereQMutexLocker lock(signalSlotLock(receiver));receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();}// 判断连接方式是否是队列连接,是队列连接就要丢入事件循环队列中处理// determine if this connection should be sent immediately or// put into the event queueif ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)|| (c->connectionType == Qt::QueuedConnection)) {queued_activate(sender, signal_index, c, argv);continue;
#if QT_CONFIG(thread)} else if (c->connectionType == Qt::BlockingQueuedConnection) {// 如果发送对象和接受对象在一个线程,使用BlockingQueuedConnection会导致死锁if (receiverInSameThread) {qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: ""Sender is %s(%p), receiver is %s(%p)",sender->metaObject()->className(), sender,receiver->metaObject()->className(), receiver);}QSemaphore semaphore;{QBasicMutexLocker locker(signalSlotLock(sender));if (!c->receiver.loadAcquire())continue;QMetaCallEvent *ev = c->isSlotObject ?new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,sender, signal_index, argv, &semaphore);QCoreApplication::postEvent(receiver, ev);}// 阻塞直至函数执行完成semaphore.acquire();continue;
#endif}// 下面是普通连接,// 如果不在一个线程,并且使用直连,那么接收者就为空QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);// 如果是槽函数对象if (c->isSlotObject) {c->slotObj->ref();struct Deleter {void operator()(QtPrivate::QSlotObjectBase *slot) const {if (slot) slot->destroyIfLastRef();}};const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};{Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());obj->call(receiver, argv);}} else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {//we compare the vtable to make sure we are not in the destructor of the object.const int method_relative = c->method_relative;const auto callFunction = c->callFunction;const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);{Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);}if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)signal_spy_set->slot_end_callback(receiver, methodIndex);} else {const int method = c->method_relative + c->method_offset;if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {signal_spy_set->slot_begin_callback(receiver, method, argv);}{Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);}if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)signal_spy_set->slot_end_callback(receiver, method);}// 此处while是循环遍历信号所连接的槽/信号} while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);// 循环两次} while (list != &signalVector->at(-1) &&//start over for all signals;((list = &signalVector->at(-1)), true));if (connections->currentConnectionId.loadRelaxed() == 0)senderDeleted = true;}if (!senderDeleted) {sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)signal_spy_set->signal_end_callback(sender, signal_index);}
}

具体分析

前面的一些基本的判断,我们就忽略,直接找到重要的地方,循环遍历信号所连接的部分。

  1. 信号槽为队列连接,我们需要将信号丢到事件循环里,待事件循环将该信号发送出去。

       if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)|| (c->connectionType == Qt::QueuedConnection)) {queued_activate(sender, signal_index, c, argv);continue;#if QT_CONFIG(thread)} 
    
  2. 当信号槽为阻塞队列连接(BlockingQueuedConnection)时,首先,我们需要判断发送和接收者是不是在一个线程,因为如果连接类型为BlockingQueuedConnection,发送者和接收者在一个线程,会导致死锁

        else if (c->connectionType == Qt::BlockingQueuedConnection) {// 如果发送对象和接受对象在一个线程,使用BlockingQueuedConnection会导致死锁if (receiverInSameThread) {qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: ""Sender is %s(%p), receiver is %s(%p)",sender->metaObject()->className(), sender,receiver->metaObject()->className(), receiver);}QSemaphore semaphore;{QBasicMutexLocker locker(signalSlotLock(sender));if (!c->receiver.loadAcquire())continue;QMetaCallEvent *ev = c->isSlotObject ?new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,sender, signal_index, argv, &semaphore);QCoreApplication::postEvent(receiver, ev);}// 阻塞直至函数执行完成semaphore.acquire();continue;#endif}
    
  3. 其他类型的连接如下:

    • 信号的连接是一个槽函数对象QSlotObject,就直接调用call函数

      	   if (c->isSlotObject) {c->slotObj->ref();struct Deleter {void operator()(QtPrivate::QSlotObjectBase *slot) const {if (slot) slot->destroyIfLastRef();}};const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};{Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());obj->call(receiver, argv);}} 
      
    • 如果是其他类型,就通过QMetaObject::InvokeMetaMethod来调用

      else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {//we compare the vtable to make sure we are not in the destructor of the object.const int method_relative = c->method_relative;const auto callFunction = c->callFunction;const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);{Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);}if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)signal_spy_set->slot_end_callback(receiver, methodIndex);} else {const int method = c->method_relative + c->method_offset;if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {signal_spy_set->slot_begin_callback(receiver, method, argv);}{Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);}if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)signal_spy_set->slot_end_callback(receiver, method);
      }
      

并且遍历整个列表,将所有相关的连接都调用一遍

queued_activate

然后我们看QueuedConnection的连接函数:

代码里,揭示了一点,就是 如果我们使用信号槽连接的方式,而信号的参数不是一个元类型或者没用qRegisterMetaType来注册类型,那么队列连接是不行的,槽函数是不会触发的

static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
{// 存储元类型参数(meta-type argument)const int *argumentTypes = c->argumentTypes.loadRelaxed();if (!argumentTypes) {// 获取对应的信号QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);// 获取信号的参数,并检查是否所有参数均为元类型(meta-type)argumentTypes = queuedConnectionTypes(m.parameterTypes());if (!argumentTypes) // cannot queue argumentsargumentTypes = &DIRECT_CONNECTION_ONLY;if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {if (argumentTypes != &DIRECT_CONNECTION_ONLY)delete [] argumentTypes;argumentTypes = c->argumentTypes.loadRelaxed();}}// 参数不符合要求,返回if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activatereturn;int nargs = 1; // include return typewhile (argumentTypes[nargs-1])++nargs;QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));if (!c->receiver.loadRelaxed()) {// the connection has been disconnected before we got the lockreturn;}if (c->isSlotObject)c->slotObj->ref();locker.unlock();// 然后通过post一个QMetaCallEvent事件到事件循环队列中去QMetaCallEvent *ev = c->isSlotObject ?new QMetaCallEvent(c->slotObj, sender, signal, nargs) :new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);void **args = ev->args();int *types = ev->types();types[0] = 0; // return typeargs[0] = nullptr; // return valueif (nargs > 1) {for (int n = 1; n < nargs; ++n)types[n] = argumentTypes[n-1];for (int n = 1; n < nargs; ++n)args[n] = QMetaType::create(types[n], argv[n]);}locker.relock();if (c->isSlotObject)c->slotObj->destroyIfLastRef();if (!c->receiver.loadRelaxed()) {// the connection has been disconnected while we were unlockedlocker.unlock();delete ev;return;}QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev);
}

代码中我们可以看到,这里是通过post一个QMetaCallEvent的事件到事件循环中,然后由事件循环去触发槽函数的调用。

结束

好了,对于信号和槽的分析,我们暂时就先分析到这,如果有问题是我上面没有说明的,可以在评论区给我评论,我看到了,看懂了,我就会更新这篇博客的。

谢谢观看 😃