QThread大概原理,源码分析

QThread有两种使用方式:

方式1:继承QThread,重写run函数,调用QThread::start(),就会创建新线程,run为入口函数。

方式2:继承QObject,使用QObject::moveToThread,配合信号/槽,在新线程中执行槽函数。

查看源码(win平台下),大概流程如下:

<QThread_win.cpp>

void QThread::start(Priority priority)
{
    d->handle = CreateThread(NULL, 0, QThreadPrivate::start, this, 0, NULL);
}


<QThread_win.cpp>   

QThreadPrivate::start()
{
    emit thr->started(QThread::QPrivateSignal());
    thr->run();
}

在 QThread_win.cpp中,start函数创建了线程,并最终调用到QThread::run()

此时如果是继承了QThread,并重写虚函数run,则会执行自定义的QThread子类的run函数,线程使用到此结束。

如果没有重写QThread的run函数,而是使用moveToThread方式,将会执行以下流程:

<QThread.cpp>

void QThread::run()
{
    (void) exec();
}

void QThread::exec()
{
    QEventLoop eventLoop;
    int returnCode = eventLoop.exec();
    
    return returnCode;
}

在QThread的线程函数中,创建并执行了事件循环QEventLoop。

                 
<QEventLoop.cpp>

int QEventLoop::exec(ProcessEventsFlags flags)
{
 while (!d->exit.loadAcquire())
        processEvents(flags | WaitForMoreEvents | EventLoopExec);

}

bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    if (!d->threadData->hasEventDispatcher())
        return false;
    return d->threadData->eventDispatcher.load()->processEvents(flags);
}

在QEventLoop::processEvents里可以发现,线程在循环遍历 d->threadData->eventDispatcher中的事件队列。

而moveToThread其实就是把QObject中的d->threadData放到新线程中,自然而然的d->threadData中的事件队列也就得以在新线程中被遍历,事件对应的处理函数就在新线程中执行了。

附moveToThread源码:

void QObject::moveToThread(QThread *targetThread)
{
    Q_D(QObject);

    if (d->threadData->thread == targetThread) {
        // object is already in this thread
        return;
    }

    if (d->parent != 0) {
        qWarning("QObject::moveToThread: Cannot move objects with a parent");
        return;
    }
    if (d->isWidget) {
        qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
        return;
    }

    QThreadData *currentData = QThreadData::current();
    QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
    if (d->threadData->thread == 0 && currentData == targetData) {
        // one exception to the rule: we allow moving objects with no thread affinity to the current thread
        currentData = d->threadData;
    } else if (d->threadData != currentData) {
        qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
                 "Cannot move to target thread (%p)\n",
                 currentData->thread.load(), d->threadData->thread.load(), targetData ? targetData->thread.load() : nullptr);

#ifdef Q_OS_MAC
        qWarning("You might be loading two sets of Qt binaries into the same process. "
                 "Check that all plugins are compiled against the right Qt binaries. Export "
                 "DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
#endif

        return;
    }

    // prepare to move
    d->moveToThread_helper();

    if (!targetData)
        targetData = new QThreadData(0);

    QOrderedMutexLocker locker(&currentData->postEventList.mutex,
                               &targetData->postEventList.mutex);

    // keep currentData alive (since we've got it locked)
    currentData->ref();

    // move the object
    d_func()->setThreadData_helper(currentData, targetData);

    locker.unlock();

    // now currentData can commit suicide if it wants to
    currentData->deref();
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值