我不确定为啥我的 QThread 模式会阻塞
Posted
技术标签:
【中文标题】我不确定为啥我的 QThread 模式会阻塞【英文标题】:I'm not sure why my QThread pattern is blocking我不确定为什么我的 QThread 模式会阻塞 【发布时间】:2013-04-18 19:23:58 【问题描述】:我已经看过很多关于 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 移动到工作线程的可能性..
对上述模式有什么想法,我可以如何改进它,以及我一般如何防止它阻塞?
【问题讨论】:
连接线程是从任何东西派生的吗? ConnectionPtr 是执行您希望在另一个线程中执行的作业的类吗?同样,conncetionPtr 是从任何东西派生的吗?从您发布的示例中,还不是很清楚... 我认为关键是如果实际上 ConnectionThread 对象不应该被移动到单独的线程。我看不到您想将哪些操作委托给工作人员。现在我没有看到工人发生任何事情。 ConnectionThread 派生自 QObject。 ConnectionPtr 也是从 QObject 派生的,它完成了我想在另一个线程中执行的工作。 【参考方案1】:编辑 1:以下是我提出的解决方案,但实际上并没有按预期工作,因为 worker 永远不会发出 finished() 信号
编辑 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 槽所示。
似乎可以解决问题,但总体而言并非完全没有错误。
【讨论】:
以上是关于我不确定为啥我的 QThread 模式会阻塞的主要内容,如果未能解决你的问题,请参考以下文章