繁体   English   中英

QThread::create 在 UI 线程上运行

[英]QThread::create running on UI Thread

我的应用程序需要多线程。 根据 Qt 的文档,有很多方法可以实现这一点。

简要概述QThread ing方法:

  1. 子类 QThread 并重新实现 run() ( doc )。

  2. 创建一个 object 继承自QObject并使用Q_OBJECT宏(用于信号/插槽)和doWork方法,创建一个QThread object,使用QObject::moveToThread(QThread*)并调用QThread::start()文档维基

  3. 对 lambda 语法使用QThread::create(Function &&f)QThread::create(std::function<>)

我选择使用第三个选项进行测试。 我还基于选项 2 实现了一个名为QThreading的多线程库,使用QWorkerThread充当 controller object, QThreadQObject作为对象。 这个库也给出了相同的结果,如下所示。


既然文档已经不在了,问题就来了。

使用QThread::create(Function &&f) ,我正在测试 QThread 是否与 UI 线程分开运行。 下面的MCVE示例:

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qsrand(0);
    QThread *thread = nullptr;
    auto threadTest = std::function<void ()> ([&]() {

        if(thread->thread() == a.thread()) {
            qDebug() << "UI Thread in use";
        } else {
            qDebug() << "Worker thread in use";
        }

        for (int var = 0; var < INT_MAX; ++var) {
            int r = qrand() % 100;
            thread->thread()->msleep(r);
            qDebug() << "[Worker Thread " << thread->thread()->currentThreadId() << "] " << r;
        }
    });
    thread = QThread::create(threadTest);
    thread->start();

    for (int var = 0; var < INT_MAX; ++var) {
        // sleep thread 0-100ms
        int r = qrand() % 100;
        a.thread()->msleep(r);
        qDebug() << "[UI Thread " << a.thread()->currentThreadId() << "] " << r;
    }

    return a.exec();
}

output 是:

UI Thread in use
[Worker Thread  0x47e4 ]  41
[UI Thread  0x10c0 ]  38
[UI Thread  0x10c0 ]  19
[UI Thread  0x10c0 ]  38
[Worker Thread  0x47e4 ]  67
[UI Thread  0x10c0 ]  37
[Worker Thread  0x47e4 ]  34
[Worker Thread  0x47e4 ]  0
[UI Thread  0x10c0 ]  55
[Worker Thread  0x47e4 ]  69
[Worker Thread  0x47e4 ]  24
[UI Thread  0x10c0 ]  97
[Worker Thread  0x47e4 ]  78
[UI Thread  0x10c0 ]  65
[Worker Thread  0x47e4 ]  58
[UI Thread  0x10c0 ]  85
[Worker Thread  0x47e4 ]  62
[UI Thread  0x10c0 ]  50
[Worker Thread  0x47e4 ]  64
[UI Thread  0x10c0 ]  12
[Worker Thread  0x47e4 ]  5
[Worker Thread  0x47e4 ]  45

注意事项

  • UI 线程 ID: 0x10c0

  • 工作线程 ID: 0x47e4

担忧来自哪里

正在使用的 UI 线程

让我困惑的是不同的线程地址,但工作线程仍然等于UI 线程。

这让我有两种解释:

  1. QThread::currentThread总是返回主机/主线程(难以置信,使得 function 有点毫无意义

  2. QThread *thread位于主 UI 线程内,因此(获取父线程)始终返回父线程,即ParentThread == WorkerThread (ParentThread)

我是否想了解QThread的工作原理?

  1. 如果您想知道它是否在主线程中运行,那么您应该将 currentThread 与 QCoreApplication 线程进行比较:
if(QCoreApplication::instance()->thread() == QThread::currentThread()) {
    qDebug() << "UI Thread in use";
} else {
    qDebug() << "Worker thread in use";
}
  1. 正如文档指出的那样,QThread 不是线程是线程处理程序:

详细说明

QThread object 管理程序中的一个控制线程。 QThreads 在run()中开始执行。 默认情况下,run() 通过调用 exec() 启动事件循环,并在线程内运行 Qt 事件循环。

此外,QThread 是一个 QObject ,它存在于父线程中,或者如果它没有父线程,则它被创建的地方,正如文档指出的那样:

线程亲和力

QObject 实例被称为具有线程亲和性,或者说它存在于某个线程中。 当 QObject 接收到排队的信号或发布的事件时,槽或事件处理程序将在 object 所在的线程中运行。

注意:如果 QObject 没有线程关联(即,如果 thread() 返回零),或者如果它存在于没有运行事件循环的线程中,则它无法接收排队信号或发布的事件。

默认情况下,QObject 存在于创建它的线程中。 可以使用 thread() 查询对象的线程亲和性,并使用 moveToThread() 更改对象的线程亲和性。

所有 QObject 必须与其父对象存在于同一线程中。 最后:

  • 如果涉及的两个 QObject 存在于不同的线程中,setParent() 将失败。
  • 当一个 QObject 被移动到另一个线程时,它的所有子对象也将被自动移动。
  • 如果 QObject 有父对象,则 moveToThread() 将失败。
  • 如果 QObjects 在 QThread::run() 中创建,它们不能成为 QThread object 的子级,因为 QThread 不存在于调用 QThread::run() 的线程中。

注意: QObject 的成员变量不会自动成为它的子变量。 必须通过将指针传递给子构造函数或调用 setParent() 来设置父子关系。 如果没有这一步,调用 moveToThread() 时对象的成员变量将保留在旧线程中。

在您的情况下,“线程” object 是一个 QObject ,它存在于主线程中,因为它没有父线程并且在那里创建并处理另一个线程。

更新:

MWE

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qsrand(0);
    auto threadTest = std::function<void ()> ([&]() {
        if(QCoreApplication::instance()->thread() == QThread::currentThread()) {
            qDebug() << "UI Thread in use";
        } else {
            qDebug() << "Worker thread in use";
        }

        for (int var = 0; var < INT_MAX; ++var) {
            int r = qrand() % 100;
            QThread::msleep(r);
            qDebug() << "[Worker Thread " << QThread::currentThreadId() << "] " << r;
        }
    });
    QThread *thread = QThread::create(threadTest);
    thread->start();

    int var = 0;
    std::function<void ()> timerTest;
    timerTest = [&](){
        int r = qrand() % 100;
        qDebug() << "[UI Thread " << QThread::currentThreadId() << "] " << r;
        ++var;
        if (var < INT_MAX)
            QTimer::singleShot(r, timerTest);
    };
    int r = qrand() % 100;
    QTimer::singleShot(r, timerTest);

    return a.exec();
}

Output:

Worker thread in use
[UI Thread  0x7fc6222993c0 ]  94
[Worker Thread  0x7fc621f62700 ]  71
[UI Thread  0x7fc6222993c0 ]  86
[Worker Thread  0x7fc621f62700 ]  94
[UI Thread  0x7fc6222993c0 ]  37
[Worker Thread  0x7fc621f62700 ]  86
...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM