我不确定为什么我的 QThread 模式被阻塞
I'm not sure why my QThread pattern is blocking
我看过很多关于QThread和在QThread之间移动qobject的帖子和文章,但是唉,它仍然让我头疼。这是我想采用的模式:
#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的实例被创建,它的开始函数是从另一个线程调用的。我们把另一个线程称为GuiThread。这意味着GuiThread拥有控制权,因此应该能够将ConnectionThread实例的所有权转移到工作线程。
我还没有完全探索的最后一种可能性是将m_connectionPtr移动到工作线程的可能性。
对上面的模式有什么想法吗,我该如何改进它,总的来说我该如何防止它阻塞?
编辑1:以下是我提出的解决方案,但它实际上并不像预期的那样工作,因为finished()信号从未由worker
编辑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是一个共享的ptr到一个'Connection',它本身是从QObject派生的,但没有父对象;同样,ConnectionThread从QObject派生,但同样没有父对象)。
由于m_connectionPtr在将来也被其他线程使用,我也不得不再次将其移回主线程,如moveConnectionPtrBack插槽所示。
似乎可以解决问题,但总体上并不是完全没有bug。
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 为什么在保护模式下继承升级不起作用
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 此模式的C++RegEx
- 如何监控QThread
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- 使用可变模板的Broadcaster/Listener模式
- c++方法参数只能在linux的发布模式下自行更改
- 资源管理设计模式
- 使用 mod_gsoap 部署服务时,如何在 Gsoap 中更改 soap 上下文的模式?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- C++ 无法在字符数组中使用 for 循环打印字母模式
- 小字符串优化(调试与发布模式)
- 可视化C++:发布模式的运行时库作为'Multi-threaded Debug DLL'
- 如何设计具有不同类型的通知和观察器的观察者模式?
- 在C++的一系列数字中查找重复模式
- 我不确定为什么我的 QThread 模式被阻塞
- QT Creator:程序在调试模式下崩溃,但在发布模式下工作,在基于QThread的程序的调试模式下有断点