• Qt多线程之QThreadData::current()理解


    QThreadData *QThreadData::current(bool createIfNecessary)
    {
        QThreadData *data = get_thread_data();
        if (!data && createIfNecessary) {
            data = new QThreadData;
            QT_TRY {
                set_thread_data(data);
                data->thread = new QAdoptedThread(data);
            } QT_CATCH(...) {
                clear_thread_data();
                data->deref();
                data = 0;
                QT_RETHROW;
            }
            data->deref();
            data->isAdopted = true;
            data->threadId.store(to_HANDLE(pthread_self()));
            if (!QCoreApplicationPrivate::theMainThread)
                QCoreApplicationPrivate::theMainThread = data->thread.load();
        }
        return data;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ● 在使用new QThreadData创建data时,其引用计数默认为1,然后通过set_thread_data设置为线程本地存储
    ● 关键就是new QAdoptedThread(data)会将data的引用计数增加到2,因为QAdoptedThread最终会调用QObject的构造函数QObject(QObjectPrivate &dd, QObject *parent)
    设置主线程为QAdoptedThread,创建的对象如果没有指定父对象,则对象的线程数据threadData为主线程的线程数据。QAdoptedThread线程是不会运行的

    void QAdoptedThread::run()
    {
        // this function should never be called
        qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    QObject::QObject(QObjectPrivate &dd, QObject *parent)
        : d_ptr(&dd)
    {
        Q_D(QObject);
        d_ptr->q_ptr = this;
        d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
        d->threadData->ref();
        if (parent) {
            QT_TRY {
                if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
                    parent = 0;
                if (d->isWidget) {
                    if (parent) {
                        d->parent = parent;
                        d->parent->d_func()->children.append(this);
                    }
                    // no events sent here, this is done at the end of the QWidget constructor
                } else {
                    setParent(parent);
                }
            } QT_CATCH(...) {
                d->threadData->deref();
                QT_RETHROW;
            }
        }
    #if QT_VERSION < 0x60000
        qt_addObject(this);
    #endif
        if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
            reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
        Q_TRACE(QObject_ctor, this);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    因为parent为nullptr,所以会再次调用QThreadData::current(),而此时调用get_thread_data获取得到的data不为空,该值也是第一次调用QThreadData::current()时分配出来的data
    将其赋值给threadData,然后调用ref()会将其引用计数增加为2

  • 相关阅读:
    如何在Android应用程序中实现高效的图片加载和缓存机制。
    设计模式-抽象工厂模式
    金仓数据库KingbaseES物理备份恢复命令选项(info命令)
    【JavaSE】String类型
    ajax请求
    数据结构与算法(三):栈与队列
    数据库Day004
    开发Chrome 插件赚钱的7个主要方式(Chrome Extension )
    PHP简单实现预定义钩子和自定义钩子
    云计算场景下,如何快速定位出虚拟机reboot/shutdown引发的故障
  • 原文地址:https://blog.csdn.net/wuli2496/article/details/132737650