将对象的亲和性从 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: 我的 connectsaveToAll 是一个 QueuedConnection。

【问题讨论】:

肯定#include &lt;QApplication&gt;?我问是因为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-&gt;thread()) 也有同样的问题。

以上是关于将对象的亲和性从 QThread 更改为主 GUI 线程的主要内容,如果未能解决你的问题,请参考以下文章

驻留在 QThread 内的 QObjects 会自动删除吗?

如何从 GUI 停止 QThread

类实例线程亲和性对其数据是不是有任何影响?

Qt线程间的信号与槽 以及 QThread

在qthread中停止长时间运行的进程

我可以在属于主线程的 QThread 中使用 waitForReadyRead 吗?