Qt无法将目标移动到线程
Qt Unable to move target to thread
我的Qt 5.7 (Windows 10)应用程序中出现了一个奇怪的错误,而导致这种行为的罪魁祸首却无处可寻:
- 被移动的对象有一个父对象——当然不是这样
- 试图将对象拉到线程而不是推它-这是错误的原因,但我不知道它来自
完整的错误信息是
QObject::moveToThread:当前线程(0x2afcca68)不是对象的线程(0 x34f4acc8)。无法移动到目标线程(0x34f4adc8)
QObject::setParent:不能设置父级,新父级在不同的位置线程
这也是我的代码:
main.cpp
#include <QApplication>
#include <QQuickItem>
#include "CustomQuickWidget.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
const QUrl source = QUrl(QLatin1String("qrc:/main"));
CustomQuickWidget widget(source);
return app.exec();
}
主要(别名 main.qml ):
// You can put any random QML content in this case really as long as it doesn't create a window since the CustomQuickWidget does that.
Rectangle {
id: window
visible: true
width: 600
height: 480
}
CustomQuickWidget.cpp
#include "CustomQuickWidget.h"
#include <QQuickItem>
CustomQuickWidget::CustomQuickWidget(const QUrl &source, QWidget *parent) : QQuickWidget(source, parent) {
// Setup the recognizer
this->airWheelRecognizer = new QAirWheelGestureRecognizer();
this->airWheelType = QGestureRecognizer::registerRecognizer(airWheelRecognizer);
// and turn on grabbing for all the supported gestures
grabGesture(airWheelType);
grabGesture(Qt::SwipeGesture);
grabGesture(Qt::TapGesture);
// Create thread and device worker
this->deviceThread = new QThread(this);
this->deviceWorker = new DeviceMapper(this, Q_NULLPTR); // NOTE: this here is NOT for parent. The constructor's signature for this class is: DeviceMapper(QObject* receiver, QList<Qt::GestureType>* gestureIDs, QObject* parent = Q_NULLPTR)
this->deviceWorker->init();
// Create timer that will trigger the data retrieval slot upon timeout
this->timer = new QTimer();
this->timer->setTimerType(Qt::PreciseTimer);
this->timer->setInterval(5);
// Move timer and device mapper to other thread
this->timer->moveToThread(this->deviceThread);
this->deviceWorker->moveToThread(this->deviceThread); // FIXME For unknown reason: QObject::moveToThread: Current thread (...) is not the object's thread. Cannot move to target thread
// Connect widget, timer and device mapper
createConnections();
// Run thread
this->deviceThread->start();
// Connect device and start data retrieval
QTimer::singleShot(0, this->deviceWorker, &(this->deviceWorker->slotToggleConnection));
QTimer::singleShot(0, this->deviceWorker, &(this->deviceWorker->slotToggleRun));
this->show();
}
CustomQuickWidget::~CustomQuickWidget()
{
if (this->deviceThread) {
this->deviceThread->quit();
this->deviceThread->wait();
}
}
void CustomQuickWidget::createConnections()
{
connect(this->timer, SIGNAL(timeout()),
this->deviceWorker, SLOT(slotRetrieveData()));
connect(this->deviceThread, SIGNAL(started()),
this->timer, SLOT(start()));
connect(this->deviceThread, SIGNAL(finished()),
this->deviceWorker, SLOT(deleteLater()));
connect(this->deviceThread, SIGNAL(finished()),
this->deviceThread, SLOT(deleteLater()));
}
bool CustomQuickWidget::event(QEvent* event) {
if (event->type() == QEvent::Gesture) {
bool res = gestureEvent(static_cast<QGestureEvent*>(event)); // Not important so not included as code here
return res;
}
return QWidget::event(event);
}
正如你所看到的,我这里有一个典型的工人线程。我已经确保我的员工(这里是DeviceMapper
)没有父母。它也在我的小部件中实例化(其中也创建了QThread
),但与计时器一起移动到线程中。
现在,除了标题中明显的问题之外,我必须提到以下内容:
-
this->timer->moveToThread(this->deviceThread);
调用 时没有此错误 - 这个非常相同的代码在另一个项目中没有任何问题,这是一个subdirs项目-一个子项目创建共享库(我在这个项目中也使用),另一个-使用库的应用程序。
我的其他应用程序和这个应用程序之间的唯一区别是使用QQuickWidget
(而不是QWidget
)和QML
。我对QML
很陌生,这也是我的第一个QQuickWidget
,所以我可能错过了一些需要"激活"的明显设置。
我还添加了
cout << this->deviceWorker->thread()->currentThreadId() << endl;
cout << this->thread()->currentThreadId() << endl;
在this->deviceWorker->moveToThread(this->deviceThread);
之前,我得到了
0x18b0
0x18b0
这意味着在moveToThread(...)
之前,我的对象属于QThread
实例化的同一个线程。在moveToThread(...)
之后打印线程ID返回相同的结果,但这是预期的,因为没有正确地将对象移动到另一个线程。
更新:
只有在发布模式下构建时才会出现错误信息,但无论构建类型如何,我都有错误仍然存在。
我已经设法解决了我的问题,当它发生的时候。
上周结束的时候,我写的应用程序突然开始工作了,所以尽管这让我很困扰,但我还是让它去吧。我既没有改变库的代码(除了我的代码中的几个注释,显然不能影响代码本身)也没有改变我的QML
应用程序的C++
代码。我所改变的只是我的QML
,但在某种程度上,这实际上与下面的C++
代码无关。我唯一改变的是构建类型。然而,上周我并没有注意到这一点。
昨天我开始做一个新项目。就在第一次运行之后,我遇到了同样的问题。我都快疯了。所以我开始分析我的代码(@Kuba Ober,抱歉,但是发布完整的代码甚至一小部分库是不可能的,否则我就会这样做(即使它有几百行实际代码(不包括注释和空行))。我检查了又检查了亲子关系,但找不到任何可以给我一点提示的东西,即使是在什么时候以及为什么会发生这种情况。我也尽我所能分析了这堆东西,但都是徒劳的。
然后我突然想到…我在上面提到过,我以前的项目在改变了它的构建类型之后突然开始工作。事实上,这就是我处境中所有罪恶的根源。我将我的库添加到我的项目(不包括与库一起属于同一个subdir
项目的初始库)的方式是在我的新项目的根目录下创建一个名为libs
的文件夹,并将相关的东西复制到它。现在,在我完成了我的库的工作并做了一些测试之后,我显然决定切换到发布版本。但是,我将release
模式下的库复制到debug
模式下的项目。因此,在几次重建和复制库之后,我发现混合使用库的应用程序的构建类型和库本身会导致这个问题。
我知道混合构建类型是一个坏主意,我通常不这样做,但这次我只是忘记了,是一个完全的意外。我不知道当X构建类型的应用程序和Y构建类型的库混合在一起时,内部发生了什么,但在我的情况下,结果是我在这个线程中发布的错误。
谢谢你的帮助。通过你的评论,我学到了很多!尽管在我的例子中调试是不必要的,但我还是要感谢您。:)
- 如何检索指向在单独线程上运行的函数的移动指针?
- 从从可调用参数创建的线程对象参数移动构造 C++11 线程
- 标准::atomic_应该如何...<std::shared_ptr>用于线程安全类的复制和移动操作?
- 将函数移动到线程(使用 lambda)时内存泄漏
- Qt 通过将对象移动到线程来跨线程发出信号
- std::move在将std::string移动到另一个线程时出错
- 使用第二个线程快速更新 GUI 窗口会通过调整窗口大小或移动窗口而崩溃
- 线程安全unique_ptr移动
- 将执行从一个线程移动到另一个线程,以实现任务并行性并在将来调用
- 在 C++03 中将 std::string 移动到 boost::线程中
- 调用移动到Qt中不同线程的QObject函数?
- 在将对象移动到另一个线程后,不能简单地删除该对象
- 安全地移动在访问其他成员的成员线程中运行 lambda 的对象
- QThread - 使用 moveToThread 将类成员移动到线程
- 移动到线程会导致问题
- Qt 线程,来自 QObject 的析构函数的崩溃移动
- 为什么 c++ 线程是可移动的,但不可复制
- 锁定线程安全队列的移动构造函数的右值参数?
- std::带可移动、不可复制参数的线程
- c++:使用多线程在控制台中移动光标