在另一个线程中创建QNetworkAccessManager

时间:2018-05-31 21:08:28

标签: c++ multithreading qt networking

我在另一个线程中创建了一个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中创建一个父代。

这样做的惯用方法是什么?

2 个答案:

答案 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