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

信号槽连接

信号槽的连接,其实内部本质还是一个回调函数,主要是维护了信号发送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-11
    if (!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进行异或,去掉UniqueConnection
        type = 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-11
        if (!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进行异或,去掉UniqueConnection
            type = 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的定义:
123

其实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);
    else
        doActivate<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 connected
        if (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);
    else
        list = &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 interfere
                QMutexLocker lock(signalSlotLock(receiver));
                receiverInSameThread = currentThreadId == td->threadId.loadRelaxed();
            }

			// 判断连接方式是否是队列连接,是队列连接就要丢入事件循环队列中处理
            // determine if this connection should be sent immediately or
            // put into the event queue
            if ((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 arguments
            argumentTypes = &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 activate
        return;
    int nargs = 1; // include return type
    while (argumentTypes[nargs-1])
        ++nargs;

    QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
    if (!c->receiver.loadRelaxed()) {
        // the connection has been disconnected before we got the lock
        return;
    }
    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 type
    args[0] = nullptr; // return value

    if (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 unlocked
        locker.unlock();
        delete ev;
        return;
    }

    QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev);
}

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

结束

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

谢谢观看 😃

待添加:
Qt::AutoConnection参数,是在什么时候进行连接类型确认的

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Qt信号机制是一种用于在对象之间进行通信的机制。在使用Qt开发程序时,我们可以通过信号连接不同对象的动作和事件,以实现对象之间的交互。 根据Qt源码和示例代码的深入剖析,我们可以了解到以下关键点: 1. 信号的基本概念:信号是一个特殊的函数,它可以被触发并发送消息。是普通的对象成员函数,可用于接收信号函数与信号函数通过连接来建立关联。 2. 信号连接:在Qt中,我们可以使用QObject::connect()函数来建立信号连接。这个函数接受发送信号的对象、信号函数的名称、接收信号的对象、函数的名称,以及连接类型等参数。 3. 信号的工作机制:Qt通过元对象系统(Meta-Object System)来实现信号的机制。在编译过程中,Qt的元对象编译器(Meta-Object Compiler,MOC)会解析包含信号的类,并生成元对象代码。这些元对象代码包含了信号的相关信息,以及用于信号连接和触发的机制。 4. 信号的触发:当发送信号的对象调用信号函数时,Qt会根据连接关系找到对应的函数,并将信号的参数传递给函数进行处理。这种触发机制是基于Qt的事件循环(Event Loop)实现的。 通过以上剖析,我们可以了解到Qt信号机制的基本原理和工作流程,并能更深入地理解其内部实现。这对于使用Qt进行程序开发和解决问题是非常有帮助的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Qt信号源码剖析](https://blog.csdn.net/m0_60259116/article/details/128551391)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Qt信号机制源码分析](https://blog.csdn.net/encourage2011/article/details/46126219)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值