Qt框架浅析之三 ------ Qt元对象系统(二)

本文深入探讨Qt中信号与槽机制的实现原理,详细解释了信号如何在moc文件中实现,以及QMetaObject::activate方法的具体工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    C++中头文件函数中的声明除非是纯虚函数,一般都在对应的cpp文件中有其函数实现,否则就会有undefined reference to XXXXXXXX。但是反观Qt的信号的声明方式:

signals:
    void  mysignal();
    这里明显是一个函数的声明,但我们也没有在对应的cpp中去实现这个函数,那么这个函数到底是在哪里实现的呢?答案就是:在moc文件中。
    下面放上一个信号的声明和对应实现的moc代码。为了排版的紧凑删除了一些空行。
    void        sigOkclicked(int nIndex);
    void        sigAddGroup(st1 qtRuleGroup);
    void        sigAddRule(st2 qtMainRule);//st1和st2分别是自己定义的一个结构体
    void        sigModifyGroup();
    void        sigModifyRule();
    对应的moc:
// SIGNAL 0
void settingDialog::sigOkclicked(int _t1){
    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void settingDialog::sigAddGroup(qt_RuleGroup _t1){
    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
// SIGNAL 2
void settingDialog::sigAddRule(qt_MainRule _t1){
    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
// SIGNAL 3
void settingDialog::sigModifyGroup(){
    QMetaObject::activate(this, &staticMetaObject, 3, 0);
}
// SIGNAL 4
void settingDialog::sigModifyRule(){
    QMetaObject::activate(this, &staticMetaObject, 4, 0);
}

    实现看起来很简单,调用的QMetaObject::activate方法,而这个staticMetaObject 在前一篇文章中提到过他是这个类默认的一个静态元对象。第三个参数是信号对应的序数,至于第四个参数为0代表无参信号,否则就是含参信号,代表相应的参数的指针。看一下Qt中这个方法的实现和其有关的调用QMetaObject::activate():

//位于qobject.cpp,此方法有其对应的N个重载函数,这是内部的实现过程
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
        int signal_index = signalOffset + local_signal_index;
        //计算信号偏移,一般根据我们的调用情况,这里回去计算信号偏移,信号偏移包括其父类的signals的计算偏移也是要计算的,signalOffset就是,local_signal_index这个就是本地的信号偏移,也就是上面的0,1,2,3,4这些参数。
    if (sender->d_func()->blockSig)
        return;
     //判断信号是否阻塞,和connect的第五个参数有关
    if (sender->d_func()->isDeclarativeSignalConnected(signal_index)
            && QAbstractDeclarativeData::signalEmitted) {
        QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender,
                                                signal_index, argv);
    }
    //

     //这里排除信号尚未链接和signal相关回调检查出错的情况 
    if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false)
        && !qt_signal_spy_callback_set.signal_begin_callback
        && !qt_signal_spy_callback_set.signal_end_callback) {
        // The possible declarative connection is done, and nothing else is connected, so:
        return;
    }
    //设置信号起始回调
    void *empty_argv[] = { 0 };
    if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
        qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
                                                         argv ? argv : empty_argv);
    }

    {
    //开互斥锁,应该是为多线程考虑
    QMutexLocker locker(signalSlotLock(sender));
    struct ConnectionListsRef {
        QObjectConnectionListVector *connectionLists;
        ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
        {
            if (connectionLists)
                ++connectionLists->inUse;
        }
        ~ConnectionListsRef()
        {
            if (!connectionLists)
                return;

            --connectionLists->inUse;
            Q_ASSERT(connectionLists->inUse >= 0);
            if (connectionLists->orphaned) {
                if (!connectionLists->inUse)
                    delete connectionLists;
            }
        }

        QObjectConnectionListVector *operator->() const { return connectionLists; }
    };
    //在函数内部声明了一个struct并重载了其->运算符
    ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
    if (!connectionLists.connectionLists) {
        locker.unlock();
        if (qt_signal_spy_callback_set.signal_end_callback != 0)
            qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
        return;
    }

    const QObjectPrivate::ConnectionList *list;
    if (signal_index count())
        list = &connectionLists->at(signal_index);
    else
        list = &connectionLists->allsignals;
    //这里得到所有signals的list。
    Qt::HANDLE currentThreadId = QThread::currentThreadId();
    //得到当前线程ID
    do {
        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;
        //采用双重循环,外面是遍历所有的信号,内层是拿到信号对应的receiver,有一个信号绑定多个槽的这种情况存在,所以两层。Connection他只保存一个sender和receiver的对应关系
        do {
            //这里是拿到对应的receiver是一个object
            if (!c->receiver)
                continue;
            //这里应该是为了数据安全用了const
            QObject * const receiver = c->receiver;
            const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;

            // determine if this connection should be sent immediately or
            // put into the event queue
            //这里看注释,情形就是,当receiver的threadId和sender的threadId一样直接发,否则将这个调用发送到事件循环
            //当时autoConnection且不同线程或者第五个参数是QueuedConnection那么是发送到县城循环,因为我们connect不加第五个参数的时候默认是AutoConnection.
            if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
                continue;
 #ifndef QT_NO_THREAD
            } else if (c->connectionType == Qt::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);
                }
                //当信号槽同线程时一定不能用BlockingQueuedConnection,否则可能死锁。
                //信号量,之后新建一个元对象调用事件的对象,并post到对应的receiver队列,并且解除掉上面的互斥锁
                QSemaphore semaphore;
                QMetaCallEvent *ev = c->isSlotObject ?
                    new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
                    new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
                QCoreApplication::postEvent(receiver, ev);
                locker.unlock();
                semaphore.acquire();
                locker.relock();
                continue;
 #endif
            }
            //inline void switchSender(QObject *receiver, QObject //*sender, int signal_absolute_id)
    //{
    //    this->receiver = receiver;
    //    currentSender.sender = sender;
    //    currentSender.signal = signal_absolute_id;//绝对信号ID
    //    currentSender.ref = 1;
    //    previousSender = //QObjectPrivate::setCurrentSender(receiver, ¤tSender);
   //     switched = true;
    //}这个是switchSender调用的源码,就是对修改receiver,previousSender
            QConnectionSenderSwitcher sw;
           if (receiverInSameThread) {
                sw.switchSender(receiver, sender, signal_index);
            }
            //看注释
            if (c->isSlotObject) {
                c->slotObj->ref();
                QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
                locker.unlock();
                obj->call(receiver, argv ? argv : empty_argv);

                // Make sure the slot object gets destroyed before the mutex is locked again, as the
                // destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool,
                // and that would deadlock if the pool happens to return the same mutex.
                obj.reset();

                locker.relock();
            } 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 methodIndex = c->method();
                const int method_relative = c->method_relative;
                const auto callFunction = c->callFunction;
                locker.unlock();
                if (qt_signal_spy_callback_set.slot_begin_callback != 0)
                    qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);
//元对象调用
                callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
//确认槽结束回调,先写到这里。
                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
                locker.relock();
            } else {
                const int method = c->method_relative + c->method_offset;
                locker.unlock();

                if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
                    qt_signal_spy_callback_set.slot_begin_callback(receiver,
                                                                method,
                                                                argv ? argv : empty_argv);
                }

                metacall(receiver, QMetaObject::InvokeMetaMethod, methodQScopedPointer, argv ? argv : empty_argv);

                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, method);

                locker.relock();
            }

            if (connectionLists->orphaned)
                break;
        } while (c != last && (c = c->nextConnectionList) != 0);

        if (connectionLists->orphaned)
            break;
    } while (list != &connectionLists->allsignals &&
        //start over for all signals;
        ((list = &connectionLists->allsignals), true));

    }

    if (qt_signal_spy_callback_set.signal_end_callback != 0)
        qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值