我在另一个线程中创建了一个QNetworkAccessManager。
该网络仅用于MyMegaThread
QNetworkAccessManager是从线程的run
方法创建的:
mp_manager.reset(new QNetworkAccessManager{this});
在创建时,我在控制台中收到了这样的消息:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
此消息完全无害,但我想知道经理应该拥有哪位父母 我怀疑它发生是因为MyMegaThread实例是在主线程中创建的,但我需要在MyMegaThread中创建一个父代。
这样做的惯用方法是什么?
答案 0 :(得分:2)
父是MyMegaThread(0x237eabd0ee0),父母的帖子是 QThread(0x237e70742a0),当前线程为MyMegaThread(0x237eabd0ee0)
该问题与HashMap
无关。
以下是重现警告的演示。
QNetworkAccessManager
输出:
#include <QDebug>
#include <QThread>
class MyMegaThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
protected:
void run() override {
qDebug()<<QThread::currentThread()<<this->thread();
new QObject(this);
}
};
// main
MyMegaThread m;
m.start();
MyMegaThread(0x60fe18) QThread(0x16a7c48)
的规则:
所有QObject必须与其父级位于同一个线程中。 因此:
如果涉及的两个QObject存在不同,则setParent()将失败 线程。当QObject被移动到另一个线程时,它的所有子线程 也将自动移动。如果移动,则moveToThread()将失败 QObject有一个父级。如果QObjects是在QThread :: run()中创建的, 他们不能成为QThread对象的子代,因为QThread 不存在于调用QThread :: run()的线程中。
http://doc.qt.io/qt-5/qobject.html#thread-affinity
必须确保运行QObject
的代码new QObject
与给定的父QThread
主题相同。
QObject
答案 1 :(得分:1)
不,这条消息根本不是无害的。您创建的对象具有空父级,并且在线程关联上没有引用,因此其thread()
方法可以随时返回悬空指针。它无法安全地使用计时器,也无法接收跨线程调用。它基本上是无用的对象,并且您要求未定义的行为进行攻击。这不应该是一个警告,而是一个失败。 Qt允许你继续,这对你有害。
这样做的惯用方法首先是不要从QThread
派生。 QThread
是一个线程句柄。它包装了一个系统资源。将您的所有功能放入常规QObject
移至QThread
。无休止的惯用方式&#34;做东西&#34;任何线程,包括主线程,都使用零持续时间计时器。请注意,零持续时间计时器与计时完全无关。它们本质上是事件循环句柄,称它们为计时器是用词不当。
即便:
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-simple-50632807
#include <QtNetwork>
class Thread final : public QThread {
Q_OBJECT
public:
void takeObject(QObject *obj) {
obj->moveToThread(this);
}
~Thread() override {
requestInterruption();
quit();
wait();
}
};
class Class : public QObject {
Q_OBJECT
QBasicTimer m_workTimer;
QNetworkAccessManager m_manager{this};
void doWorkChunk() {
qDebug() << "tick...";
QThread::sleep(1); // emulate a blocking operation
}
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != m_workTimer.timerId())
return;
doWorkChunk();
}
public:
explicit Class(QObject *parent = {}) : QObject(parent) {
m_workTimer.start(0, this);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Class object;
Thread workThread;
workThread.start();
workThread.takeObject(&object);
QTimer::singleShot(3000, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
警告相对温和,表示内部计时器句柄泄漏。有关解决方法,请参阅this answer。