c++ gui programming with qt 中关于 QThread的用法的限制
下面这句话的翻译不清
QObject is reentrant, but there are three constraints to keep in mind:

Child QObjects must be created in their parent's thread.
In particular, this means that the objects created in a secondary thread must never be created with the QThread object as their parent, because that object was created in another thread (either the main thread or a different secondary thread).

中文翻译为 QObject 的子对象必须在他的父对象线程中创建 。应改为“QObject 的子对象必须在他的父对象所在的线程中创建”
就好理解了。
因为QThread 对象声明时是 在主线程或 其他线程中,在Qthread对象中声明的对象以该Qthread为父亲的对象和该QThread的对象不在同一线程。

也可以这样理解,只有 QThread::run()才是 这个线程的启动入口,并以该函数结束退出该线程的运行。而QThread 仍是其定义所在的线程中的一个对象。

实例:
#ifndef THREADTEST2_H
#define THREADTEST2_H
#include
#include

class Class1 : public QObject
{
public:
Class1(QObject* parent) : QObject(parent){}
};

class ThreadTest2 : public QThread
{
public:
ThreadTest2()
{
qDebug() << "ThreadTest2::ThreadTest2, thread = " << QThread::currentThread();
}

void run() override

{

qDebug() << "ThreadTest2::run, thread = " << QThread::currentThread();//**

qDebug() << "ThreadTest2::run, ThreadTest2 thread = " << this->thread();//**

m_class = new Class1(this);//父对象

}

private:
Class1* m_class = nullptr;
};

#endif // THREADTEST2_H

#include
#include "qthreadtest.h"
#include "threadtest2.h"
#include

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

ThreadTest2 thread2;
thread2.start();

return app.exec();

}


编译结果
ThreadTest2::ThreadTest2, thread = QThread(0x2864244cbd0)
ThreadTest2::run, thread = QThread(0x8d9d4ff7a8)
ThreadTest2::run, ThreadTest2 thread = QThread(0x2864244cbd0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QThread(0x8d9d4ff7a8), parent's thread is QThread(0x2864244cbd0), current thread is QThread(0x8d9d4ff7a8)
————————————————
由运行结果看出 thread2(ThreadTest2)属于主线程(QThread(0x2864244cbd0)),我们尝试在 QThread(0x2864244cbd0)线程中为属于(QThread(0x2864244cbd0))的 thread2 对象创建子对象,所以出问题了。

————————————————

解决方法

那么我们可以如何避免出现这种问题呢,方法有很多种,下面介绍几种:

1. 创建对象时不指定父对象

既然问题出在为父对象创建子对象过程中,那么我们创建对象时不指定父对象不就好了,修改如下:
#ifndef THREADTEST2_H
#define THREADTEST2_H
#include
#include

class Class1 : public QObject
{
public:
Class1(QObject* parent = nullptr) : QObject(parent){}
};

class ThreadTest2 : public QThread
{
public:
ThreadTest2()
{
qDebug() << "ThreadTest2::ThreadTest2, thread = " << QThread::currentThread();
}

void run() override
{
    qDebug() << "ThreadTest2::run, thread = " << QThread::currentThread();
    qDebug() << "ThreadTest2::run, ThreadTest2 thread = " << this->thread();
    m_class = new Class1();
}

private:
Class1* m_class = nullptr;
};

#endif // THREADTEST2_H
显然这种方式不是很好,不指定父对象,创建的m_class对象的释放就要由自己管理了。我们可以看看其他方法。

2. 使用moveToThread设置对象绑定的线程

既然是因为在不同的线程创建子对象出问题了,那么我们将父对象属于的线程与执行线程设置为同一个线程不就好了吗。修改如下
#include
#include "qthreadtest.h"
#include "threadtest2.h"
#include

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

ThreadTest2 thread2;
thread2.moveToThread(&thread2);
thread2.start();

return app.exec();

}
运行结果
ThreadTest2::ThreadTest2, thread = QThread(0x20f230c0d80)
ThreadTest2::run, thread = QThread(0xb5db97fb58)
ThreadTest2::run, ThreadTest2 thread = QThread(0xb5db97fb58)
可以看到thread2绑定的线程变为QThread(0xb5db97fb58),与run执行线程属于同一个线程了。

3. 将子对象的创建放到启动执行线程的线程中完成

既然是因为在不同的线程创建子对象出问题了,我们可以将子对象的创建放到父对象绑定的线程中创建就好了,就上面例子而言简单的方法就是将子对象的创建放到父对象的构造函数中
#ifndef THREADTEST2_H
#define THREADTEST2_H
#include
#include

class Class1 : public QObject
{
public:
Class1(QObject* parent = nullptr) : QObject(parent){}
};

class ThreadTest2 : public QThread
{
public:
ThreadTest2()
{
m_class = new Class1(this);
qDebug() << "ThreadTest2::ThreadTest2, thread = " << QThread::currentThread();
}

void run() override
{
    qDebug() << "ThreadTest2::run, thread = " << QThread::currentThread();
    qDebug() << "ThreadTest2::run, ThreadTest2 thread = " << this->thread();
}

private:
Class1* m_class = nullptr;
};

#endif // THREADTEST2_H

参考以下博文
版权声明:本文为CSDN博主「-Davis」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35511927/article/details/121422908

posted on 2023-11-16 09:55  keleman  阅读(1400)  评论(0编辑  收藏  举报