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

打印 上一主题 下一主题

主题 529|帖子 529|积分 1587

信号槽连接


目录

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

下面列举一种信号的连接方式,来大致讲解一下信号的连接过程。
  1. //Connect a signal to a pointer to qobject member function
  2.     // QtPrivate::FunctionPointer<Func1>::Object返回发送信号的对象类型
  3.     template <typename Func1, typename Func2>
  4.     static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
  5.                                      const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
  6.                                      Qt::ConnectionType type = Qt::AutoConnection)
  7.     {
  8.         typedef QtPrivate::FunctionPointer<Func1> SignalType;
  9.         typedef QtPrivate::FunctionPointer<Func2> SlotType;
  10.         Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
  11.                           "No Q_OBJECT in the class with the signal");
  12.         //compilation error if the arguments does not match.
  13.         // 检查信号和槽参数是否一致
  14.         Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
  15.                           "The slot requires more arguments than the signal provides.");
  16.                 // 检查信号和槽参数是否兼容
  17.         Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
  18.                           "Signal and slot arguments are not compatible.");
  19.                 // 检查信号和槽的返回值是否兼容
  20.                 Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
  21.                           "Return type of the slot is not compatible with the return type of the signal.");
  22.         const int *types = nullptr;
  23.                 // SignalType -> QtPrivate::FunctionPointer<Func1>
  24.                 // QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types() 返回信号参数的值对应的元类型id列表
  25.         if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
  26.             types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
  27.         return connectImpl(sender, reinterpret_cast<void **>(&signal),
  28.                            receiver, reinterpret_cast<void **>(&slot),
  29.                            new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
  30.                                            typename SignalType::ReturnType>(slot),
  31.                             type, types, &SignalType::Object::staticMetaObject);
  32.     }
复制代码
上面主要都是一些基本的信号连接的判断,主要是:

  • 信号和槽的参数数量
  • 信号和槽的参数是否兼容
  • 信号和槽的返回值是否兼容
然后获取信号参数所对应的元类型Id,再就到了一个信号连接的具体内部实现中
  1. QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
  2.                                              const QObject *receiver, void **slot,
  3.                                              QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
  4.                                              const int *types, const QMetaObject *senderMetaObject)
  5. {
  6.     if (!signal) {
  7.         qWarning("QObject::connect: invalid nullptr parameter");
  8.         if (slotObj)
  9.             slotObj->destroyIfLastRef();
  10.         return QMetaObject::Connection();
  11.     }
  12.     int signal_index = -1;
  13.     void *args[] = { &signal_index, signal };
  14.         // 根据调用来判断是否存在信号,如果当前类没有就去父类中寻找
  15.         // 直到找到信号或者是最基层的类
  16.         // 找到信号的index和信号的对象
  17.     for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
  18.         senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
  19.         if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
  20.             break;
  21.     }
  22.     if (!senderMetaObject) {
  23.         qWarning("QObject::connect: signal not found in %s", sender->metaObject()->className());
  24.         slotObj->destroyIfLastRef();
  25.         return QMetaObject::Connection(nullptr);
  26.     }
  27.         // 信号下标
  28.     signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
  29.     return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
  30. }
复制代码
同样,我们对这个函数进行分析,第一个片段是对信号发送者是否为空指针的一个判断
  1. if (!signal) {
  2.     qWarning("QObject::connect: invalid nullptr parameter");
  3.     if (slotObj)
  4.         slotObj->destroyIfLastRef();
  5.     return QMetaObject::Connection();
  6. }
复制代码
第二个片段是去找到信号发送者(sender)的元对象类型(Meta Object)以及信号在对象信号中的位置。如果当前对象没有该信号,就去其父类对象去找。直到找到为止。
  1. for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
  2.     senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
  3.     if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject)->signalCount)
  4.         break;
  5. }
复制代码
然后就是进一步调用其内部实现:
  1. QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
  2.                                              const QObject *receiver, void **slot,
  3.                                              QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
  4.                                              const int *types, const QMetaObject *senderMetaObject)
  5. {
  6.         // 发送对象、接收对象、槽函数对象、信号发送的元对象都不为空 2023-3-11
  7.     if (!sender || !receiver || !slotObj || !senderMetaObject) {
  8.                 // 任意一个为空,报错且清理空间,并返回
  9.         const char *senderString = sender ? sender->metaObject()->className()
  10.                                           : senderMetaObject ? senderMetaObject->className()
  11.                                           : "Unknown";
  12.         const char *receiverString = receiver ? receiver->metaObject()->className()
  13.                                               : "Unknown";
  14.         qWarning("QObject::connect(%s, %s): invalid nullptr parameter", senderString, receiverString);
  15.         if (slotObj)
  16.             slotObj->destroyIfLastRef();
  17.         return QMetaObject::Connection();
  18.     }
  19.         // 去掉const的发送和接受对象
  20.     QObject *s = const_cast<QObject *>(sender);
  21.     QObject *r = const_cast<QObject *>(receiver);
  22.         // 顺序锁,按照顺序依次去对mutex去上锁
  23.         // 这里依次对发送和接收者的信号去上锁
  24.     QOrderedMutexLocker locker(signalSlotLock(sender),
  25.                                signalSlotLock(receiver));
  26.     if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
  27.                 // ObjectPrivate::get(s) 获取s对应的d指针
  28.                 // connections 维护了所有的信号槽连接
  29.         QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
  30.         if (connections->signalVectorCount() > signal_index) {
  31.                         // 获取信号的连接
  32.             const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
  33.                         // 循环遍历
  34.             while (c2) {
  35.                                 // 如果已经存在信号和槽的连接,且为uniqueConnection,则返回
  36.                 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
  37.                     slotObj->destroyIfLastRef();
  38.                     return QMetaObject::Connection();
  39.                 }
  40.                 c2 = c2->nextConnectionList.loadRelaxed();
  41.             }
  42.         }
  43.                 // 将type与UniqueConnection进行异或,去掉UniqueConnection
  44.         type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
  45.     }
  46.         // 创建一个新的连接
  47.     std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
  48.     c->sender = s;
  49.     c->signal_index = signal_index;
  50.     QThreadData *td = r->d_func()->threadData;
  51.     td->ref();
  52.     c->receiverThreadData.storeRelaxed(td);
  53.     c->receiver.storeRelaxed(r);
  54.     c->slotObj = slotObj;
  55.     c->connectionType = type;
  56.     c->isSlotObject = true;
  57.     if (types) {
  58.         c->argumentTypes.storeRelaxed(types);
  59.         c->ownArgumentTypes = false;
  60.     }
  61.         // 将新创建的连接加到连接列表中
  62.     QObjectPrivate::get(s)->addConnection(signal_index, c.get());
  63.     QMetaObject::Connection ret(c.release());
  64.     locker.unlock();
  65.     QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
  66.     Q_ASSERT(method.isValid());
  67.     s->connectNotify(method);
  68.     return ret;
  69. }
复制代码
同样第一个部分也是对一些个空值的判断
  1.         // 发送对象、接收对象、槽函数对象、信号发送的元对象都不为空 2023-3-11
  2.     if (!sender || !receiver || !slotObj || !senderMetaObject) {
  3.                 // 任意一个为空,报错且清理空间,并返回
  4.         const char *senderString = sender ? sender->metaObject()->className()
  5.                                           : senderMetaObject ? senderMetaObject->className()
  6.                                           : "Unknown";
  7.         const char *receiverString = receiver ? receiver->metaObject()->className()
  8.                                               : "Unknown";
  9.         qWarning("QObject::connect(%s, %s): invalid nullptr parameter", senderString, receiverString);
  10.         if (slotObj)
  11.             slotObj->destroyIfLastRef();
  12.         return QMetaObject::Connection();
  13.     }
复制代码
然后就是一个if判断,主要是对Qt::UniqueConnection连接的一些处理,获取当前对象的信号连接列表,并判断当前要连接的信号和槽,之前有没有被连接过,如果有过连接,就直接返回。
  1. if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
  2.                 // ObjectPrivate::get(s) 获取s对应的d指针
  3.                 // connections 维护了所有的信号槽连接
  4.         QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
  5.         if (connections->signalVectorCount() > signal_index) {
  6.                         // 获取信号的连接
  7.             const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
  8.                         // 循环遍历
  9.             while (c2) {
  10.                                 // 如果已经存在信号和槽的连接,且为uniqueConnection,则返回
  11.                 if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
  12.                     slotObj->destroyIfLastRef();
  13.                     return QMetaObject::Connection();
  14.                 }
  15.                 c2 = c2->nextConnectionList.loadRelaxed();
  16.             }
  17.         }
  18.                 // 将type与UniqueConnection进行异或,去掉UniqueConnection
  19.         type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
  20.     }
复制代码
最后才是创建一个Connection并将连接的信息以及信号的参数设置进去,然后保存到对象的信号连接容器里。
  1. // 创建一个新的连接
  2.     std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
  3.     c->sender = s;
  4.     c->signal_index = signal_index;
  5.     QThreadData *td = r->d_func()->threadData;
  6.     td->ref();
  7.     c->receiverThreadData.storeRelaxed(td);
  8.     c->receiver.storeRelaxed(r);
  9.     c->slotObj = slotObj;
  10.     c->connectionType = type;
  11.     c->isSlotObject = true;
  12.     if (types) {
  13.         c->argumentTypes.storeRelaxed(types);
  14.         c->ownArgumentTypes = false;
  15.     }
  16.         // 将新创建的连接加到连接列表中
  17.     QObjectPrivate::get(s)->addConnection(signal_index, c.get());
  18.     QMetaObject::Connection ret(c.release());
  19.     locker.unlock();
  20.     QMetaMethod method = QMetaObjectPrivate::signal(senderMetaObject, signal_index);
  21.     Q_ASSERT(method.isValid());
  22.     s->connectNotify(method);
  23.     return ret;
复制代码
2 槽的调用

定义一个信号,使用moc生成moc文件之后,我们可以看到信号函数的定义如下:
  1. // SIGNAL 0
  2. void MainWindow::sgnTestFor()
  3. {
  4.     QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
  5. }
复制代码
我们发射一个信号的时候,我们会这样写:
  1. emit sgnTestFor();
复制代码
我们可以看关于emit的定义:

其实emit关键字什么都没有做,只是标识了一下当前发射了信号。所以本质上,发射一个信号实际上就是直接调用了这个信号的函数,也就是调用了QMetaObject中的activate函数。
函数如下:
  1. void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
  2.                            void **argv)
  3. {
  4.     int signal_index = local_signal_index + QMetaObjectPrivate::signalOffset(m);
  5.     if (Q_UNLIKELY(qt_signal_spy_callback_set.loadRelaxed()))
  6.         doActivate<true>(sender, signal_index, argv);
  7.     else
  8.         doActivate<false>(sender, signal_index, argv);
  9. }
复制代码
上面的qt_signal_spy_callback_set暂时不清楚是什么玩意,所以我们不管,直接看具体的doActive函数
  1. template <bool callbacks_enabled>
  2. void doActivate(QObject *sender, int signal_index, void **argv)
  3. {
  4.         // 首先获取QObject的private对象
  5.     QObjectPrivate *sp = QObjectPrivate::get(sender);
  6.         // 判断信号是否阻塞
  7.     if (sp->blockSig)
  8.         return;
  9.     Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
  10.     if (sp->isDeclarativeSignalConnected(signal_index)
  11.             && QAbstractDeclarativeData::signalEmitted) {
  12.         Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
  13.         QAbstractDeclarativeData::signalEmitted(sp->declarativeData, sender,
  14.                                                 signal_index, argv);
  15.     }
  16.     const QSignalSpyCallbackSet *signal_spy_set = callbacks_enabled ? qt_signal_spy_callback_set.loadAcquire() : nullptr;
  17.     void *empty_argv[] = { nullptr };
  18.     if (!argv)
  19.         argv = empty_argv;
  20.     if (!sp->maybeSignalConnected(signal_index)) {
  21.         // The possible declarative connection is done, and nothing else is connected
  22.         if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
  23.             signal_spy_set->signal_begin_callback(sender, signal_index, argv);
  24.         if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
  25.             signal_spy_set->signal_end_callback(sender, signal_index);
  26.         return;
  27.     }
  28.     if (callbacks_enabled && signal_spy_set->signal_begin_callback != nullptr)
  29.         signal_spy_set->signal_begin_callback(sender, signal_index, argv);
  30.     bool senderDeleted = false;
  31.     {
  32.     Q_ASSERT(sp->connections.loadAcquire());
  33.     QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
  34.     QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
  35.         // 信号连接列表,因为一个信号可能连接了多个槽       
  36.     const QObjectPrivate::ConnectionList *list;
  37.     if (signal_index < signalVector->count())
  38.         list = &signalVector->at(signal_index);
  39.     else
  40.         list = &signalVector->at(-1);
  41.         // 判断当前线程是不是信号发送者的线程
  42.     Qt::HANDLE currentThreadId = QThread::currentThreadId();
  43.     bool inSenderThread = currentThreadId == QObjectPrivate::get(sender)->threadData.loadRelaxed()->threadId.loadRelaxed();
  44.         //
  45.     // We need to check against the highest connection id to ensure that signals added
  46.     // during the signal emission are not emitted in this emission.
  47.     uint highestConnectionId = connections->currentConnectionId.loadRelaxed();
  48.         // 此处也就代表着,一个信号连接的多个槽函数,或者多个连接,会以连接的顺序被触发
  49.     do {
  50.         QObjectPrivate::Connection *c = list->first.loadRelaxed();
  51.         if (!c)
  52.             continue;
  53.         do {
  54.             QObject * const receiver = c->receiver.loadRelaxed();
  55.             if (!receiver)
  56.                 continue;
  57.             QThreadData *td = c->receiverThreadData.loadRelaxed();
  58.             if (!td)
  59.                 continue;
  60.             bool receiverInSameThread;
  61.                         // 判断发送和接受是不是同一个线程
  62.             if (inSenderThread) {
  63.                 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
  64.             } else {
  65.                 // need to lock before reading the threadId, because moveToThread() could interfere
  66.                 QMutexLocker lock(signalSlotLock(receiver));
  67.                 receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
  68.             }
  69.                         // 判断连接方式是否是队列连接,是队列连接就要丢入事件循环队列中处理
  70.             // determine if this connection should be sent immediately or
  71.             // put into the event queue
  72.             if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
  73.                 || (c->connectionType == Qt::QueuedConnection)) {
  74.                 queued_activate(sender, signal_index, c, argv);
  75.                 continue;
  76. #if QT_CONFIG(thread)
  77.             } else if (c->connectionType == Qt::BlockingQueuedConnection) {
  78.                     // 如果发送对象和接受对象在一个线程,使用BlockingQueuedConnection会导致死锁
  79.                 if (receiverInSameThread) {
  80.                     qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
  81.                     "Sender is %s(%p), receiver is %s(%p)",
  82.                     sender->metaObject()->className(), sender,
  83.                     receiver->metaObject()->className(), receiver);
  84.                 }
  85.                 QSemaphore semaphore;
  86.                 {
  87.                     QBasicMutexLocker locker(signalSlotLock(sender));
  88.                     if (!c->receiver.loadAcquire())
  89.                         continue;
  90.                     QMetaCallEvent *ev = c->isSlotObject ?
  91.                         new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
  92.                         new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
  93.                                            sender, signal_index, argv, &semaphore);
  94.                     QCoreApplication::postEvent(receiver, ev);
  95.                 }
  96.                                 // 阻塞直至函数执行完成
  97.                 semaphore.acquire();
  98.                 continue;
  99. #endif
  100.             }
  101.                         // 下面是普通连接,
  102.                         // 如果不在一个线程,并且使用直连,那么接收者就为空
  103.             QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
  104.                         // 如果是槽函数对象
  105.             if (c->isSlotObject) {
  106.                 c->slotObj->ref();
  107.                 struct Deleter {
  108.                     void operator()(QtPrivate::QSlotObjectBase *slot) const {
  109.                         if (slot) slot->destroyIfLastRef();
  110.                     }
  111.                 };
  112.                 const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};
  113.                 {
  114.                     Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());
  115.                     obj->call(receiver, argv);
  116.                 }
  117.             } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
  118.                 //we compare the vtable to make sure we are not in the destructor of the object.
  119.                 const int method_relative = c->method_relative;
  120.                 const auto callFunction = c->callFunction;
  121.                 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
  122.                 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
  123.                     signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
  124.                 {
  125.                     Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
  126.                     callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
  127.                 }
  128.                 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
  129.                     signal_spy_set->slot_end_callback(receiver, methodIndex);
  130.             } else {
  131.                 const int method = c->method_relative + c->method_offset;
  132.                 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
  133.                     signal_spy_set->slot_begin_callback(receiver, method, argv);
  134.                 }
  135.                 {
  136.                     Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
  137.                     QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
  138.                 }
  139.                 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
  140.                     signal_spy_set->slot_end_callback(receiver, method);
  141.             }
  142.                 // 此处while是循环遍历信号所连接的槽/信号
  143.         } while ((c = c->nextConnectionList.loadRelaxed()) != nullptr && c->id <= highestConnectionId);
  144.         // 循环两次
  145.     } while (list != &signalVector->at(-1) &&
  146.         //start over for all signals;
  147.         ((list = &signalVector->at(-1)), true));
  148.         if (connections->currentConnectionId.loadRelaxed() == 0)
  149.             senderDeleted = true;
  150.     }
  151.     if (!senderDeleted) {
  152.         sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
  153.         if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
  154.             signal_spy_set->signal_end_callback(sender, signal_index);
  155.     }
  156. }
复制代码
前面的一些基本的判断,我们就忽略,直接找到重要的地方,循环遍历信号所连接的部分。

  • 当信号槽为队列连接,我们需要将信号丢到事件循环里,待事件循环将该信号发送出去。
    1. if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
    2.                 || (c->connectionType == Qt::QueuedConnection)) {
    3.                 queued_activate(sender, signal_index, c, argv);
    4.                 continue;
    5. #if QT_CONFIG(thread)
    6. }
    复制代码
  • 当信号槽为阻塞队列连接(BlockingQueuedConnection)时,首先,我们需要判断发送和接收者是不是在一个线程,因为如果连接类型为BlockingQueuedConnection,发送者和接收者在一个线程,会导致死锁。
    1. else if (c->connectionType == Qt::BlockingQueuedConnection) {
    2.                     // 如果发送对象和接受对象在一个线程,使用BlockingQueuedConnection会导致死锁
    3.                 if (receiverInSameThread) {
    4.                     qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
    5.                     "Sender is %s(%p), receiver is %s(%p)",
    6.                     sender->metaObject()->className(), sender,
    7.                     receiver->metaObject()->className(), receiver);
    8.                 }
    9.                 QSemaphore semaphore;
    10.                 {
    11.                     QBasicMutexLocker locker(signalSlotLock(sender));
    12.                     if (!c->receiver.loadAcquire())
    13.                         continue;
    14.                     QMetaCallEvent *ev = c->isSlotObject ?
    15.                         new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
    16.                         new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction,
    17.                                            sender, signal_index, argv, &semaphore);
    18.                     QCoreApplication::postEvent(receiver, ev);
    19.                 }
    20.                                 // 阻塞直至函数执行完成
    21.                 semaphore.acquire();
    22.                 continue;
    23. #endif
    24. }
    复制代码
其他类型的连接如下:

  • 信号的连接是一个槽函数对象QSlotObject,就直接调用call函数
    1. if (c->isSlotObject) {
    2.                 c->slotObj->ref();
    3.                 struct Deleter {
    4.                     void operator()(QtPrivate::QSlotObjectBase *slot) const {
    5.                         if (slot) slot->destroyIfLastRef();
    6.                     }
    7.                 };
    8.                 const std::unique_ptr<QtPrivate::QSlotObjectBase, Deleter> obj{c->slotObj};
    9.                 {
    10.                     Q_TRACE_SCOPE(QMetaObject_activate_slot_functor, obj.get());
    11.                     obj->call(receiver, argv);
    12.                 }
    13.             }
    复制代码
  • 如果是其他类型,就通过QMetaObject::InvokeMetaMethod来调用
    1. else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
    2.                 //we compare the vtable to make sure we are not in the destructor of the object.
    3.                 const int method_relative = c->method_relative;
    4.                 const auto callFunction = c->callFunction;
    5.                 const int methodIndex = (Q_HAS_TRACEPOINTS || callbacks_enabled) ? c->method() : 0;
    6.                 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr)
    7.                     signal_spy_set->slot_begin_callback(receiver, methodIndex, argv);
    8.                 {
    9.                     Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, methodIndex);
    10.                     callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);
    11.                 }
    12.                 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
    13.                     signal_spy_set->slot_end_callback(receiver, methodIndex);
    14.             } else {
    15.                 const int method = c->method_relative + c->method_offset;
    16.                 if (callbacks_enabled && signal_spy_set->slot_begin_callback != nullptr) {
    17.                     signal_spy_set->slot_begin_callback(receiver, method, argv);
    18.                 }
    19.                 {
    20.                     Q_TRACE_SCOPE(QMetaObject_activate_slot, receiver, method);
    21.                     QMetaObject::metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);
    22.                 }
    23.                 if (callbacks_enabled && signal_spy_set->slot_end_callback != nullptr)
    24.                     signal_spy_set->slot_end_callback(receiver, method);
    25. }
    复制代码
并且遍历整个列表,将所有相关的连接都调用一遍。
然后我们看QueuedConnection的连接函数:
代码里,揭示了一点,就是如果我们使用信号槽连接的方式,而信号的参数不是一个元类型或者没用qRegisterMetaType来注册类型,那么队列连接是不行的,槽函数是不会触发的。
  1. static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
  2. {
  3.         // 存储元类型参数(meta-type argument)
  4.     const int *argumentTypes = c->argumentTypes.loadRelaxed();
  5.     if (!argumentTypes) {
  6.                 // 获取对应的信号
  7.         QMetaMethod m = QMetaObjectPrivate::signal(sender->metaObject(), signal);
  8.                 // 获取信号的参数,并检查是否所有参数均为元类型(meta-type)
  9.         argumentTypes = queuedConnectionTypes(m.parameterTypes());
  10.         if (!argumentTypes) // cannot queue arguments
  11.             argumentTypes = &DIRECT_CONNECTION_ONLY;
  12.         if (!c->argumentTypes.testAndSetOrdered(nullptr, argumentTypes)) {
  13.             if (argumentTypes != &DIRECT_CONNECTION_ONLY)
  14.                 delete [] argumentTypes;
  15.             argumentTypes = c->argumentTypes.loadRelaxed();
  16.         }
  17.     }
  18.         // 参数不符合要求,返回
  19.     if (argumentTypes == &DIRECT_CONNECTION_ONLY) // cannot activate
  20.         return;
  21.     int nargs = 1; // include return type
  22.     while (argumentTypes[nargs-1])
  23.         ++nargs;
  24.     QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
  25.     if (!c->receiver.loadRelaxed()) {
  26.         // the connection has been disconnected before we got the lock
  27.         return;
  28.     }
  29.     if (c->isSlotObject)
  30.         c->slotObj->ref();
  31.     locker.unlock();
  32.         // 然后通过post一个QMetaCallEvent事件到事件循环队列中去
  33.     QMetaCallEvent *ev = c->isSlotObject ?
  34.         new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
  35.         new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
  36.     void **args = ev->args();
  37.     int *types = ev->types();
  38.     types[0] = 0; // return type
  39.     args[0] = nullptr; // return value
  40.     if (nargs > 1) {
  41.         for (int n = 1; n < nargs; ++n)
  42.             types[n] = argumentTypes[n-1];
  43.         for (int n = 1; n < nargs; ++n)
  44.             args[n] = QMetaType::create(types[n], argv[n]);
  45.     }
  46.     locker.relock();
  47.     if (c->isSlotObject)
  48.         c->slotObj->destroyIfLastRef();
  49.     if (!c->receiver.loadRelaxed()) {
  50.         // the connection has been disconnected while we were unlocked
  51.         locker.unlock();
  52.         delete ev;
  53.         return;
  54.     }
  55.     QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev);
  56. }
复制代码
代码中我们可以看到,这里是通过post一个QMetaCallEvent的事件到事件循环中,然后由事件循环去触发槽函数的调用。
好了,对于信号和槽的分析,我们暂时就先分析到这,如果有问题是我上面没有说明的,可以在评论区给我评论,我看到了,看懂了,我就会更新这篇博客的。

谢谢观看
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

水军大提督

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表