54

I am using Qt 4.6.0 (32 bit) under Windows 7 Ultimate. Consider the following QThread:

Interface

class ResultThread : public QThread
{
Q_OBJECT

    QString _post_data;
    QNetworkAccessManager _net_acc_mgr;

signals:
    void onFinished(QNetworkReply* net_reply);

private slots:
    void onReplyFinished(QNetworkReply* net_reply);

public:
    ResultThread();

    void run();
    void setPostData(const QString& post_data);
};

Implementation

ResultThread::ResultThread() : _net_acc_mgr(this)
{
    connect(&_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(onReplyFinished(QNetworkReply*)));
}

void ResultThread::onReplyFinished(QNetworkReply* net_reply)
{
    emit onFinished(net_reply);
}

void ResultThread::setPostData(const QString& post_data)
{
    _post_data = post_data;
}

void ResultThread::run()
{
    _net_acc_mgr.post(QNetworkRequest(QUrl("http://[omitted]")),
                      QByteArray(_post_data.toStdString().c_str()));
}

Whenever _net_acc_mgr.post() is executed in ResultThread::run(), I got the following Application Output in Qt Creator:

QObject: Cannot create children for a parent that is in a different thread.

(Parent is QNetworkAccessManager(0x22fe58), parent's thread is QThread(0x9284190), current thread is ResultThread(0x22fe48)

What does this mean? How to solve it?

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Donotalo
  • 12,748
  • 25
  • 83
  • 121

2 Answers2

68

The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.

This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.

Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.

The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.

fat
  • 6,435
  • 5
  • 44
  • 70
Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • 2
    This works but looks weird to me. I declared _net_acc_mgr inside `ResultThread` but `ResultThread::run()` executes in another thread! Why Qt is designed in this way? Particularly, why `ResultThread::run()` runs in another thread rather than `ResultThread`? – Donotalo Jul 17 '10 at 05:21
  • 22
    Welcome to the world of multithreading. Actually, the thread in which ResultThread is created is always different to the one, where ResultThread::run() is executed. Think about it, it doesn't make sense any other way. The whole purpose of QThread is to run something in a different thread. To do this, you need to set up the data for the new thread somewhere and this happens in the thread where you create ResultThread. When this is done, you are able to run the thread - of course it runs then in a different thread... – Gunther Piez Jul 17 '10 at 08:33
  • 2
    Then, if all code is moved to the slot, the slot will execute in the parent thread. Why we create the child thread? – diverger Jul 18 '16 at 03:38
  • 1
    You might misunderstand how QThread is intedend to be used. In your case it might be better to not implement the run method but instead move a worker QObject (which has to be different from the QThread object) to the QThread. Take a look at the examples in the documentation: http://doc.qt.io/qt-5/qthread.html#details – relgukxilef Sep 01 '16 at 13:04
  • Why do you say "Create a slot in the object where QNetworkRequestManager belongs to" when you could just say "Create a slot in the object in ResultThread"? It is obvious (at least to me) that QNetworkRequestManager object belongs to ResultThread. – avernus Apr 25 '22 at 10:50
0

I received this error message when I forgot to set the QNetworkRequestManager's parent.

nam = new QNetworkAccessManager(this);