我在QThread上看过很多帖子和文章,在QThreads之间移动QObjects,但是它仍然令我头痛。这是我试图采用的模式:
#include "connectionthread.h"
#include <cassert>
ConnectionThread::ConnectionThread(ConnectionPtr const &connectionPtr) :
worker(NULL),
m_connectionPtr(connectionPtr)
{
connect(this, SIGNAL(executeSignal()), this, SLOT(loginProcess()));
}
void
ConnectionThread::start()
{
if(worker) {
if(worker->isRunning()) {
worker->quit();
}
delete worker;
}
worker = new QThread;
connect(worker, SIGNAL(started()), this, SLOT(run()));
worker->start();
}
void
ConnectionThread::run()
{
emit executeSignal();
}
void
ConnectionThread::loginProcess()
{
m_connectionPtr->Connect();
}
现在在主GUI线程中创建了一个这样的实例,但是当最终调用loginProcess时,它会阻塞直到完成,这会导致我的应用程序的GUI挂起。注意,如果我将逻辑代码直接放入run函数并省略如下信号,则没有观察到差异: -
void
ConnectionThread::run()
{
m_connectionPtr->Connect();
}
所以我假设我需要将'this'移动到名为worker的线程,例如:
void
ConnectionThread::start()
{
if(worker) {
if(worker->isRunning()) {
worker->quit();
}
delete worker;
}
worker = new QThread;
this->moveToThread(worker);
connect(worker, SIGNAL(started()), this, SLOT(run()));
worker->start();
}
但是这给了我
QObject: Cannot create children for a parent that is in a different thread.
我不确定为什么会这样,但是因为创建了一个ConnectionThread实例并且从另一个线程调用了它的start函数。让我们称之为另一个线程GuiThread。这意味着GuiThread具有控制权,因此应该能够将ConnectionThread实例的所有权转移到工作线程。
我尚未完全探索的最后一种可能性是将m_connectionPtr移动到工作线程的可能性。
对上述模式的任何想法,我如何改进它,以及一般如何阻止它阻止?
答案 0 :(得分:0)
编辑1:以下是我提出的解决方案,但实际上并没有按预期工作,因为工作人员从未发出完成的()信号
编辑2:修复了触发完成的信号,但我仍然无法将m_connectionPtr移回moveConnectionPtrBack中的主线程。给出错误“QObject :: moveToThread:当前线程(0x102900380)不是对象的线程(0x10493b740)。无法移动到目标线程(0x102900380)”
所以,我想我已经弄明白该怎么做了:解决方案似乎是将ConnectionPtr的线程所有权转移给工作线程:
#include "connectionthread.h"
ConnectionThread::ConnectionThread(ConnectionPtr const &connectionPtr) :
worker(NULL),
m_connectionPtr(connectionPtr)
{
// EDIT 2 added bit -- m_connectionPtr sends signal when work finished
connect(m_connectionPtr.data(),
SIGNAL(connectFinishedSignal()), this, SLOT(quitThread()));
}
void
ConnectionThread::start()
{
if(worker) {
if(worker->isRunning()) {
worker->quit();
}
delete worker;
}
worker = new QThread;
m_connectionPtr->moveToThread(worker);
connect(worker, SIGNAL(started()), m_connectionPtr.data(), SLOT(Connect()));
connect(worker, SIGNAL(finished()), this, SLOT(moveConnectionPtrBack()));
worker->start();
}
void
ConnectionThread::moveConnectionPtrBack()
{
// this call failing still
m_connectionPtr->moveToThread(QApplication::instance()->thread());
}
// EDIT 2 added bit; quitting causes worker to send finished signal() which causes
// correct triggering of moveConnectionPtrBack() function
void
ConnectionThread::quitThread()
{
worker->quit();
}
(注意m_connectionPtr是'Connection'的共享ptr,它本身是从QObject派生但没有父对象;同样ConnectionThread是从QObject派生的,但同样没有父对象。)
由于m_connectionPtr将来也被其他线程使用,我还必须将其再次移回主线程,如moveConnectionPtrBack插槽所示。
似乎可以做到这一点,但总的来说并非完全没有错误。