Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QObject::moveToThread() with child objects! [SOLVED]
QtWS25 Last Chance

QObject::moveToThread() with child objects! [SOLVED]

Scheduled Pinned Locked Moved General and Desktop
20 Posts 3 Posters 30.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Seraph
    wrote on last edited by
    #1

    Hey there,

    I have a thread class ComThread deriving from QThread just implementing the void run() method.

    @void run()
    {
    exec()
    }@

    Now I have an init() function called in main() that creates a comThread object and some objects by parsing a config file.
    One of these objects is a Connection.
    A connection defines an interface for sending/receiving data independent of the protocol.
    The Connection class holds either a QTcpSocket or QTcpServer (depends on the config).
    Once the connection object is instantiated, connection->moveToThread(comThread) is called.
    At the end of init() i call comThread->start()

    Now the problem:
    If I start the application and i try to send something via the connection, QT returns the following:
    QObject::connect: Cannot queue argument of type 'QByteArray&'
    (Make sure 'QByteArray' is registered using qRegisterMetaType() ).

    The QByteArray& is related to the received(QByteArray&) signal emitted by the connection object.
    Why is that? Without moving the connection to the thread all works fine!

    Now the second problem:
    Connection is derived from QObject
    The Connection constructor for the server connection looks like that:

    @
    Connection::Connection(QObject* parent): QObject(parent)
    {
    _socket = new QTcpServer(this); //if i change this to parent no error occurs
    }@

    When i start the program and the connection is moved to the thread Qt returns:
    QObject: Cannot create children for a parent that is in a different Thread

    ???

    Thanks for every answer!

    1 Reply Last reply
    0
    • T Offline
      T Offline
      terenty
      wrote on last edited by
      #2

      Hi! Regarding the second problem:
      "The official documentation":http://qt-project.org/doc/qt-4.8/qobject.html#moveToThread says that you can’t use QObject::moveToThread() on an object which has a parent - maybe its the cause of your problem?

      1 Reply Last reply
      0
      • S Offline
        S Offline
        Seraph
        wrote on last edited by
        #3

        Yes, but it also says: Changes the thread affinity for this object and its children
        My Connection does not have a parent. It is 0.

        But it is complaining!

        QObject: Cannot create children for a parent that is in a different Thread
        It says, that the complaining object's parent is QTCPSocket which means that it goes deeper down than i can handle!?

        Here is the tree:
        @Connection - Parent is 0
        |- QTcpSocket(Parent is Connection)
        |- QTcpServer(Parent is Connection)@

        What am I doing wrong?

        1 Reply Last reply
        0
        • K Offline
          K Offline
          KA51O
          wrote on last edited by
          #4

          This is an excellent example for the pitfalls of subclassing from QThread.
          Read these article:
          "You're doing it wrong":http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
          "best practise for QThread":http://qt-project.org/wiki/QThreads_general_usage
          "doc note in QThread reference":http://qt-project.org/doc/qt-4.8/QThread.html#notes

          1 Reply Last reply
          0
          • T Offline
            T Offline
            terenty
            wrote on last edited by
            #5

            I am a bit confused,
            "Best practise for QThread":http://qt-project.org/wiki/QThreads_general_usage warns that we should NEVER allocate heap objects (using new) in the constructor of the QObject worker(to be moved into another thread) while "the official docs":http://qt-project.org/doc/qt-4.8/qobject.html#moveToThread says that moveToThread changes the thread affinity for this object and its children.
            In another "forum thread":http://qt-project.org/forums/viewthread/22200/ a guy allocated timer(using new) in worker constructor and everithing worked fine.
            Could someone explain this please?

            1 Reply Last reply
            0
            • K Offline
              K Offline
              KA51O
              wrote on last edited by
              #6

              If you create objects on the heap in your worker objects constructor and do not make them children of the worker object then they are not moved. If they are children of the worker object then you should be fine as far as I understood.

              I think the advise in the best practise article is mistakenly taken from experiences with subclassing QThread were it is true that you should not create heap objects in the constructor but only in the run functions implementation (that is unless you call moveToThread() on your own QThread subclass and the heap objects are children of the QThread subclass).

              I know it is confusing at first, but believe me the worker object approach will make your life a whole lot easier. Just remember to only use signal-slot communication between threads.

              For simple tasks which are in a fire and forget kind of manner or which easily fit in one function you can also consider using "QRunnable":http://qt-project.org/doc/qt-4.8/qrunnable.html or "QtConcurrent":http://qt-project.org/doc/qt-4.8/qtconcurrent.html.

              1 Reply Last reply
              0
              • T Offline
                T Offline
                terenty
                wrote on last edited by
                #7

                KA51O, thanks for the clarification. Your summary is probably the safest, I will stick to it.

                Seraph, could you please keep us updated on your progress :)

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  Seraph
                  wrote on last edited by
                  #8

                  Yes I will as soon as possible! Thanks for the answers so far!

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    Seraph
                    wrote on last edited by
                    #9

                    Hi there.

                    OK. I read all the articles and i think i got QThreads right from the beginning on.
                    My problem has another much deeper root.

                    I made up a sand box code:
                    @

                    class BasicThread: public QThread
                    {
                    public:
                    BasicThread(QObject* parent=0): QObject(parent){ }
                    protected:
                    virtual void run() { exec(); }
                    };

                    int main(int argc, char* argv[])
                    {
                    QApplication *a = new QApplication(argc, argv);

                    BasicThread* thread = new BasicThread();

                    QTcpServer* socket = new QTcpServer();

                    socket->moveToThread(thread);

                    socket->listen(QHostAddress::Any, 1234);

                    thread->start();

                    return a->exec();
                    }
                    @

                    Now QT streams the following error:
                    QObject: Cannot create children for a parent that is in a different thread!
                    (Parent is QTcpServer ...) ...

                    OK. So far so bad.
                    QTcpServer::listen() seems to create a new object! Which would make sense!
                    If i remove the line: @socket->listen(QHostAddress::Any, 1234);@
                    the error wont appear!

                    My solution for now is to catch the started() signal of the thread and call the line in the catching slot. But this makes things very complicated for me! I would have to give all new generated sockets to a worker (in a list) and the process() or work() method would call listen() of each socket in this list. That also means, that i need a worker for each different class which will be instanciated in my init method (see first post).

                    Any ideas to do that easier with QT?

                    1 Reply Last reply
                    0
                    • K Offline
                      K Offline
                      KA51O
                      wrote on last edited by
                      #10

                      [quote author="Seraph" date="1354789060"]
                      @
                      class BasicThread: public QThread
                      {
                      public:
                      BasicThread(QObject* parent=0): QObject(parent){ } // <------ why not QThread(parent) ?
                      protected:
                      virtual void run() { exec(); } // this is already QThreads default implementation
                      };
                      @
                      [/quote]

                      Why are you deriving from QThread and then only use QObjects constructor for the constructor of your subclass?

                      Also you don't need to subclass QThread at all for your use case. This would be sufficient:
                      @
                      int main(int argc, char* argv[])
                      {
                      QApplication *a = new QApplication(argc, argv);

                      QThread* thread = new QThread(a);

                      QTcpServer* socket = new QTcpServer();

                      socket->moveToThread(thread);

                      connect(thread, SIGNAL(finished()), socket, SLOT(deleteLater()));
                      connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

                      socket->listen(QHostAddress::Any, 1234);

                      thread->start();

                      return a->exec();
                      }
                      @

                      1 Reply Last reply
                      0
                      • S Offline
                        S Offline
                        Seraph
                        wrote on last edited by
                        #11

                        Hi KA510,

                        First of all, sorry! It is ofcourse a mistake: It should be QThread not QObject (Would not even compile i guess)

                        I derive the QThread class because of run() calling exec(). If i don't, the application will crash. This is when i do not use QThread(a)!

                        The problem is still there! KA510 did you test your code? Did you get the same result and error message?

                        Thanks for your effort

                        1 Reply Last reply
                        0
                        • K Offline
                          K Offline
                          KA51O
                          wrote on last edited by
                          #12

                          Sry I didn't test the code, that was just brain to terminal. Did you debug the test app? Where does it crash and what's the call stack like? It's just a guess but maybe this has to do with the fact that the main eventloop only starts after the a->exec() call.
                          I did something very similar in different applications and it always worked just fine.

                          1 Reply Last reply
                          0
                          • S Offline
                            S Offline
                            Seraph
                            wrote on last edited by
                            #13

                            The crash is not my problem! The problem is still the fact that i cannot call the listen() method of QTcpServer without getting the error
                            QObject: Cannot create children for a parent that is in a different thread!
                            (Parent is QTcpServer …) …

                            Because listen() appears to create a new QObject inside which tries to set the QTcpServer instance as parent!???

                            1 Reply Last reply
                            0
                            • K Offline
                              K Offline
                              KA51O
                              wrote on last edited by
                              #14

                              Try implementing a wrapper for the QTcpServer. Something like this:
                              @
                              class MyServer : public QObject
                              {
                              Q_OBJECT
                              public:
                              MyServer(QObject* a_parent);

                              public slots:
                              void startServer();
                              void stopServer();
                              void handleNewConnection();
                              signals:
                              void newConnectionSg(QTcpSocket* a_pSocket);
                              private:
                              QTcpServer* m_pServer;
                              };

                              MyServer::MyServer(QObject* a_parent)
                              : QObject(a_parent)
                              {
                              m_pServer = new QTcpServer(this);
                              connect(m_pServer, SIGNAL(newConnection()), this, SLOT(handleNewConnection()));
                              }

                              void MyServer::handleNewConnection()
                              {
                              emit newConnectionSg(m_pServer->nextPendingConnection());
                              }

                              void MyServer::startServer()
                              {
                              m_pServer->listen(QHostAddress::Any, 1234);
                              }

                              void MyServer::stopServer()
                              {
                              m_pServer->close();
                              }
                              @
                              Then do this.
                              @
                              int main(int argc, char* argv[])
                              {
                              QApplication *a = new QApplication(argc, argv);

                               QThread* thread = new QThread(a);
                               
                               MyServer* server = new MyServer();
                               
                               server->moveToThread(thread);
                               
                               connect(thread, SIGNAL(started()), server, SLOT(startServer()));
                               connect(thread, SIGNAL(finished()), server, SLOT(stopServer()));
                               connect(thread, SIGNAL(finished()), server, SLOT(deleteLater()));
                               connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
                               
                               QTimer::singleShot(1000, thread, SLOT(start()));
                               
                               return a->exec(&#41;;
                              }
                              

                              @

                              BUT it really isn't neccessary to move the QTcpServer to another thread because of its asynchronous interface. What you could do is move the sockets that QTcpServer::nextPendingConnection() returns into threads of their own (again not neccessary for simple use cases because of asynchronous design).

                              1 Reply Last reply
                              0
                              • S Offline
                                S Offline
                                Seraph
                                wrote on last edited by
                                #15

                                In my framework i already got the sockets wrapped.
                                I also tried the same thing with QTcpSocket and connectToHost()
                                Same result.

                                But i now found a way to get rid of the error!

                                I'm now calling listen() before calling move to thread!

                                @
                                int main(int argc, char* argv[])
                                {
                                QApplication *a = new QApplication(argc, argv);

                                QThread* thread = new QThread(a);

                                QTcpServer* socket = new QTcpServer();

                                QObject::connect(thread, SIGNAL(finished()), socket, SLOT(deleteLater()));
                                QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

                                socket->listen(QHostAddress::Any, 1234);

                                socket->moveToThread(thread); //this line has to come AFTER calling socket->listen()

                                thread->start();

                                return a->exec();
                                }@

                                I am testing the full functionality right now.

                                1 Reply Last reply
                                0
                                • K Offline
                                  K Offline
                                  KA51O
                                  wrote on last edited by
                                  #16

                                  Just out of curiosity have you tried calling listen(..) after starting the thread ?

                                  1 Reply Last reply
                                  0
                                  • S Offline
                                    S Offline
                                    Seraph
                                    wrote on last edited by
                                    #17

                                    Calling listen AFTER staring the thread also worked!

                                    1 Reply Last reply
                                    0
                                    • K Offline
                                      K Offline
                                      KA51O
                                      wrote on last edited by
                                      #18

                                      Hmm must have got something to do with thread context I guess. If you call it before moveToThread it's executed in the context of the main thread (running eventloop) if you call it after starting your new thread it's executed in the new threads context (also running eventloop). If you call it in between moveToThread() and start() it's already in the new threads context but the eventloop of this thread is not running yet.

                                      Just a guess though. I would really like to know the exact reason.

                                      1 Reply Last reply
                                      0
                                      • S Offline
                                        S Offline
                                        Seraph
                                        wrote on last edited by
                                        #19

                                        Yes me, too.

                                        Ok. For the QTcpServer it works fine. The QTcpSocket gives me an error when sending/receiving stuff:
                                        QSocketNotifier: socket notifiers cannot be enabled from another thread (????)

                                        What does that mean at all? Beside this error it is all working fine! It is sending and receiving and signals are sent and received!

                                        1 Reply Last reply
                                        0
                                        • S Offline
                                          S Offline
                                          Seraph
                                          wrote on last edited by
                                          #20

                                          OK. It is by the way senseless to put a socket into a thread!
                                          I am now using the thread-worker approach and it is working perfectly. If a signal is connected to a QObject (the worker) which is in another thread (one can use QObject::moveToThread()) the signal will be appended to a queue. The thread worker will receive the signals when the previos signal has been proceeded completely!

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved