将对象的亲和性从 QThread 更改为主 GUI 线程
Posted
技术标签:
【中文标题】将对象的亲和性从 QThread 更改为主 GUI 线程【英文标题】:Change affinity of an Object from a QThread to Main GUI Thread 【发布时间】:2018-05-17 13:11:17 【问题描述】:我有一个 Qt GUI 应用程序,其中包含一些类和一个主程序。对于计算量大的写入操作之一,我创建了一个QThread
作为类成员。像这样的:
//class members
std::unique_ptr<QThread> m_savingThread;
std::unique_ptr<DiffClass> m_controller;
connect(this, &SomeClass::saveAll, m_controller.get(), &DiffClass::saveToAll, Qt::QueuedConnection);
connect(m_controller.get(), &DiffClass::done, m_savingThread.get(), &QThread::quit);
void SomeClass::saveToFile()
//Saving thread
qDebug() << "From main thread:" << QThread::currentThreadId();
m_controller->moveToThread(m_savingThread.get());
m_savingThread->start();
qRegisterMetaType<std::string>("std::string");
emit saveAll(someString);
上面的代码工作正常。但是一旦保存操作完成,我需要将 m_controller
对象返回到主 GUI 线程。我可以找到类似的东西
here。简而言之,它指出由于QThread
只能将对象“推送”到线程中,因此我需要将其再次从当前工作线程推送到主线程中。
void DiffClass::saveToAll(someString)
qDebug() << "From worker thread:" << QThread::currentThreadId();
/*saving operation*/
moveToThread(QApplication::instance()->thread()); //Error QCoreApplication has no member thread()
emit done();
有没有办法将对象的亲和性改回主线程?
编辑 1: 我的 connect
到 saveToAll
是一个 QueuedConnection。
【问题讨论】:
你肯定有#include <QApplication>
?我问是因为QApplication::instance()
返回QCoreApplication *
,所以我希望错误消息是QCoreApplication has no member thread()
。
抱歉打错字了....你是对的。
【参考方案1】:
首先,为什么要来回切换线程关联?这似乎没有实际意义。
除此之外,应该可以将其更改为另一个威胁,条件是对象没有父对象并且从当前亲和线程调用moveToThread()
。
您可以使用从任何线程指定的QMetaObject::invokeMethod()
和Qt::QueuedConnection
来安排从当前关联线程执行槽,这会将关联从正确的线程更改为您作为参数传递的任何线程。
但是看看您是如何尝试从类内部更改它的,只要通过信号/插槽机制(而不是直接从几乎任何线程)调用 saveToAll()
,它应该可以按预期工作。
//Error QCoreApplication has no member thread()
根据文档,它肯定是这样做的。
【讨论】:
我需要切换的原因是我的m_controller
附加到很多其他插槽。我的保存功能偶尔会由用户触发,但由于它是一个繁重的过程,它会冻结我的 GUI,直到操作完成。所以,我需要这个对象在一个线程上运行,只是为了这个进程。
好吧,在这种情况下,您应该考虑为该功能单独使用一个专用对象和线程。来回移动它不是一个好主意。不要惹麻烦。
你是对的!但也不能这样做,因为我的对象包含用于写入文件的所有相关数据。
您可以从任何线程访问任何对象数据。如果存在竞争条件的危险,只需使用互斥锁来保护相关数据访问。
是的 saveToAll()
使用信号/槽调用。此外,我对moveToThread(qApp->thread())
也有同样的问题。以上是关于将对象的亲和性从 QThread 更改为主 GUI 线程的主要内容,如果未能解决你的问题,请参考以下文章