![](/img/trans.png)
[英]QNetworkAccessManager freezes GUI even when in another thread
[英]Creating QNetworkAccessManager in another thread
我在另一个线程中创建了一个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中创建父代。
这样做的惯用方法是什么?
Parent是MyMegaThread(0x237eabd0ee0),父节点的线程是QThread(0x237e70742a0),当前线程是MyMegaThread(0x237eabd0ee0)
该问题与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都必须与其父级位于同一个线程中。 所以:
如果涉及的两个QObject存在于不同的线程中,则setParent()将失败。 当QObject移动到另一个线程时,它的所有子节点也将自动移动。 如果QObject具有父级,则moveToThread()将失败。 如果在QThread :: run()中创建了QObject,它们就不能成为QThread对象的子节点,因为QThread不存在于调用QThread :: run()的线程中。
http://doc.qt.io/qt-5/qobject.html#thread-affinity
必须确保运行QThread
此代码new QObject
与给定的父QObject
线程相同。
mp_manager.reset(new QNetworkAccessManager{this});
不,这条消息根本不是无害的。 您创建的对象具有空父项,并且在线程关联上没有引用,因此其thread()
方法可以随时返回悬空指针。 它无法安全地使用计时器,也无法接收跨线程调用。 它基本上是无用的对象,你要求未定义的行为进行攻击。 这不应该是警告,而是失败。 Qt允许你继续,这对你有害。
这样做的惯用方法首先不是从QThread
派生出来的。 QThread
是一个线程句柄。 它包装了一个系统资源。 将所有功能放入常规QObject
移动到QThread
。 在任何线程(包括主线程)上无休止地“做东西”的惯用方法是使用零持续时间计时器。 请注意,零持续时间计时器与计时完全无关。 它们本质上是事件循环句柄,称它们为计时器是用词不当。
以机智:
// 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
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
警告QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
相对良性并指示内部计时器句柄泄漏。 有关解决方法,请参阅此答案 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.