Domanda

After reading the documentation I came across this:

The child of a QObject must always be created in the thread where the parent was created. This implies, among other things, that you should never pass the QThread object (this) as the parent of an object created in the thread (since the QThread object itself was created in another thread).

I'm not really sure what this means so I made a few examples and was wondering where this would apply.

A.

class MyThread : public QThread {
    MyThread(QObject *parent = 0) : QThread(parent) {
        QNetworkAccessManager *test = new QNetworkAccessManager (this); 
       // here I assume that this child(test) will have the main thread (creator of MyThread)
       // as it's parent and it will go horrible wrong. 
    }
    ....
}

B.

class MyThread : public QThread {
    QNetworkAccessManager *test;
    MyThread(QObject *parent = 0) : QThread(parent) {}

    void run {
       test = new QNetworkAccessManager(this); 
       // will the main thread be the parent here aswell?
       // if I remove "this" this will work since its created in the thread (not the main thread)
    }
    ....
}

Okey, but how about this?

Notice that these object will be created and started like this:

MyThread *fakeThread = new MyThread; // should I or should I not pass "this" as a parent here?
QThread realThread;

fakeThread->moveToThread(&realThread);

realThread.start();
QMetaObject::invokeMethod(fakeThread, "start", Qt::QueuedConnection);

C.

class MyThread : public QObject {
    MyThread(QObject *parent = 0) : QObject(parent) {
        QNetworkAccessManager *test = new QNetworkAccessManager(this); 
       // I assume this constructor still will be create the the QNAM as a child to 
       // the main thread and it will not work
    }

    void start {
        ....
    }
}

D.

class MyThread : public QObject {
    QNetworkAccessManager *test;
    MyThread(QObject *parent = 0) : QObject(parent) {}

    void start {
       test = new QNetworkAccessManager(this); 
       // What about now? 
    }
    ....
}

I really want to implement the option D so that I have a hirerchy of objects that can easily be deleted. For example if I wanna read a big number of files, and I want all of them to be de-allocated when the thread dies.

Also, what is the main difference between the QThread derived version and the one where you move the QObject to a thread? The documentation always states the do and don't when working with Qthread, but I'm a bit unsure about this.

My biggest issue now is that I have a class that is derived from QObject that will be moved to a thread. In that object I create a another object. That object contains a QNetworkAccessManager and a QFile. Where would I pass "this" as a parent, or should I not do that at all when being in a thread? Please explain.

At the moment, the object(let's call it RestHandler) that belongs to object(uploader, which is a thread) is created on the heap. This is because most of the function uses it and if it's created in the header file on the stack, its parent will be the main thread. The in the RestHandler a QNetworkAccessManager will be created on the stack.

Edit:

After reading the answers I tried to create both the restHandler and the QNetworkAccessManager on the stack and then move them. The output was the following:

Resthandeler constructor: restHandler created in thread QThread(0x22d5e8) with a accessManager in thread QThread(0x22d5e8) current location QThread(0x22d5e8)

Then when I try to move the resthandler I get the following warning:

QObject::moveToThread: Current thread (0x1fbf0e0) is not the object's thread (0x22d5e8).
Cannot move to target thread (0x1fbf0e0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x42a477c), parent's thread is QThread(0x22d5e8), current thread is QThread(0x4196f98)

I guess there is no way of solving this? The program seems to run and the slots are being called in the right threads, but it seems to be a question of time before it crashes.

È stato utile?

Soluzione

From the Threads and QObjects documentation:

Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module. For example, you cannot start a timer or connect a socket in a thread that is not the object's thread.

For you, this means your QNetworkAccessManager needs to be in the thread where you will be connecting sockets etc. It can't be a child of your MyThread object, and if it initialized in your constructor, it needs to be moved the MyThread after the thread has been started.

You must ensure that all objects created in a thread are deleted before you delete the QThread. This can be done easily by creating the objects on the stack in your run() implementation.

Is there a reason you're allocating the QNetworkAccessManager on the heap? Can you have it be a plain member (on the stack) instead?

From the QNetworkAccessManager docs:

The Network Access API is constructed around one QNetworkAccessManager object, which holds the common configuration and settings for the requests it sends. It contains the proxy and cache configuration, as well as the signals related to such issues, and reply signals that can be used to monitor the progress of a network operation. One QNetworkAccessManager should be enough for the whole Qt application.

This suggests to me that you may want to rethink the design decision behind having multiple threads with this type of object, and whether you can follow the intended usage pattern instead. You can still have many worker threads that connect via threadsafe signal/slot connections to a single instance of the QNetworkAccessManager which belongs in the main thread.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top