Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML multithread client with c++ integration

QML multithread client with c++ integration

Scheduled Pinned Locked Moved Solved QML and Qt Quick
18 Posts 4 Posters 3.7k 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.
  • P PouryaTorabi

    I tried @LeLev method, So first I made another class named backend, and registered it to my qml with:

    backend *backendHandler = new backend();
    engine.rootContext()->setContextProperty("backendHandler", backendHandler);
    

    Then in one of backend's functions I create an instance of the TCPhandler class and moved it in a new thread:

    QThread *TcpThread = new QThread();
    tcpHandler *tcp = new tcpHandler();
    tcp->moveToThread(TcpThread);
    TcpThread->start();
    

    In my tcpHandler class I create an instance of the Qtcpsocket. but again the UI froze. The part which cause it is:

    socket->write(mydata);
    

    Since mydata is some large datas. So I tried to write the threads to see if the socket's thread has change or not, and saw that the thread of the created socket is the same as the main thread but the tcpHandler is different. I tried to force the socket to move to tcpHandler's thread by using:

    socket->moveToThread(this->thread());
    

    but it gave the error: "Cannot create children for a parent that is in a different thread".
    So my problem is that the part which froze my UI is socket->write(mydata) which I can't move to another thread and must be in the main thread. The qml engine must also be in the main thread, so what option do I have?
    Actually what I want to do is to upload a large file to the server. (might be around 500mb)

    ODБOïO Offline
    ODБOïO Offline
    ODБOï
    wrote on last edited by
    #7

    @PouryaTorabi said in QML multithread client with c++ integration:

    in one of backend's functions I create an instance of the TCPhandler class and moved it in a new thread

    TcpThread and tcp must be members of your backend class.

    @PouryaTorabi said in QML multithread client with c++ integration:

    In my tcpHandler class I create an instance of the Qtcpsocket. but again the UI froze. The part which cause it is:
    socket->write(mydata);

    how do you call your tcps methodes from the backend ? With signal/slot connections ?

    Can you show how you're doing it please ?

    1 Reply Last reply
    1
    • P PouryaTorabi

      I tried @LeLev method, So first I made another class named backend, and registered it to my qml with:

      backend *backendHandler = new backend();
      engine.rootContext()->setContextProperty("backendHandler", backendHandler);
      

      Then in one of backend's functions I create an instance of the TCPhandler class and moved it in a new thread:

      QThread *TcpThread = new QThread();
      tcpHandler *tcp = new tcpHandler();
      tcp->moveToThread(TcpThread);
      TcpThread->start();
      

      In my tcpHandler class I create an instance of the Qtcpsocket. but again the UI froze. The part which cause it is:

      socket->write(mydata);
      

      Since mydata is some large datas. So I tried to write the threads to see if the socket's thread has change or not, and saw that the thread of the created socket is the same as the main thread but the tcpHandler is different. I tried to force the socket to move to tcpHandler's thread by using:

      socket->moveToThread(this->thread());
      

      but it gave the error: "Cannot create children for a parent that is in a different thread".
      So my problem is that the part which froze my UI is socket->write(mydata) which I can't move to another thread and must be in the main thread. The qml engine must also be in the main thread, so what option do I have?
      Actually what I want to do is to upload a large file to the server. (might be around 500mb)

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by
      #8

      @PouryaTorabi
      To avoid problems and conflicts, refrain from stack variables and constructer initialization in the class that is supposed to be moved to another thread.

      instead create a function to initialize stuff, for example void initClass() then inside your wrapper class connect the started signal of your thread to that initClass function.

      QThread *TcpThread = new QThread();
      tcpHandler *tcp = new tcpHandler();
      tcp->moveToThread(TcpThread);
      connect(TcpThread, &QThread::started, tcp, &tcpHandler::initClass);
      TcpThread->start();
      

      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      1 Reply Last reply
      1
      • P PouryaTorabi

        I tried @LeLev method, So first I made another class named backend, and registered it to my qml with:

        backend *backendHandler = new backend();
        engine.rootContext()->setContextProperty("backendHandler", backendHandler);
        

        Then in one of backend's functions I create an instance of the TCPhandler class and moved it in a new thread:

        QThread *TcpThread = new QThread();
        tcpHandler *tcp = new tcpHandler();
        tcp->moveToThread(TcpThread);
        TcpThread->start();
        

        In my tcpHandler class I create an instance of the Qtcpsocket. but again the UI froze. The part which cause it is:

        socket->write(mydata);
        

        Since mydata is some large datas. So I tried to write the threads to see if the socket's thread has change or not, and saw that the thread of the created socket is the same as the main thread but the tcpHandler is different. I tried to force the socket to move to tcpHandler's thread by using:

        socket->moveToThread(this->thread());
        

        but it gave the error: "Cannot create children for a parent that is in a different thread".
        So my problem is that the part which froze my UI is socket->write(mydata) which I can't move to another thread and must be in the main thread. The qml engine must also be in the main thread, so what option do I have?
        Actually what I want to do is to upload a large file to the server. (might be around 500mb)

        ODБOïO Offline
        ODБOïO Offline
        ODБOï
        wrote on last edited by ODБOï
        #9

        @PouryaTorabi said in QML multithread client with c++ integration:

        froze

        inside your backend don't call tcps methods directly like this :

        //backend.cpp

        tcp->slotName();
        

        use signal/slot instead

        1 Reply Last reply
        1
        • P PouryaTorabi

          I tried @LeLev method, So first I made another class named backend, and registered it to my qml with:

          backend *backendHandler = new backend();
          engine.rootContext()->setContextProperty("backendHandler", backendHandler);
          

          Then in one of backend's functions I create an instance of the TCPhandler class and moved it in a new thread:

          QThread *TcpThread = new QThread();
          tcpHandler *tcp = new tcpHandler();
          tcp->moveToThread(TcpThread);
          TcpThread->start();
          

          In my tcpHandler class I create an instance of the Qtcpsocket. but again the UI froze. The part which cause it is:

          socket->write(mydata);
          

          Since mydata is some large datas. So I tried to write the threads to see if the socket's thread has change or not, and saw that the thread of the created socket is the same as the main thread but the tcpHandler is different. I tried to force the socket to move to tcpHandler's thread by using:

          socket->moveToThread(this->thread());
          

          but it gave the error: "Cannot create children for a parent that is in a different thread".
          So my problem is that the part which froze my UI is socket->write(mydata) which I can't move to another thread and must be in the main thread. The qml engine must also be in the main thread, so what option do I have?
          Actually what I want to do is to upload a large file to the server. (might be around 500mb)

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #10

          Sockets are special, you can't create them in some thread and then move them to another. Instead, you must create them in the thread that they're going to live in. So, to do that, queue a call in your worker object, which call is going to trigger the socket's creation and initialization. Something along those lines:

          class MyWorker : public QObject
          {
              Q_OBJECT
          
          public slots:
               void initSocket();
          
          private:
              QTcpSocket * socket = nullptr;
          };
          
          void MyWorker::initSocket()
          {
              socket  = new QTcpSocket(this);
              // ... More stuff ...
          }
          

          which is used like this (or equivalent):

          MyWorker * worker = new MyWorker;
          
          QThread workerThread;
          workerThread.start();
          
          worker->moveToThread(&workerThread);
          QMetaObject::invokeMethod(worker, &MyWorker::initSocket, Qt::QueuedConnection);
          

          @J.Hilk said in QML multithread client with c++ integration:

          To avoid problems and conflicts, refrain from stack variables

          Just no! Stack is harder, better, faster, stronger. ;)

          Read and abide by the Qt Code of Conduct

          J.HilkJ 1 Reply Last reply
          3
          • kshegunovK kshegunov

            Sockets are special, you can't create them in some thread and then move them to another. Instead, you must create them in the thread that they're going to live in. So, to do that, queue a call in your worker object, which call is going to trigger the socket's creation and initialization. Something along those lines:

            class MyWorker : public QObject
            {
                Q_OBJECT
            
            public slots:
                 void initSocket();
            
            private:
                QTcpSocket * socket = nullptr;
            };
            
            void MyWorker::initSocket()
            {
                socket  = new QTcpSocket(this);
                // ... More stuff ...
            }
            

            which is used like this (or equivalent):

            MyWorker * worker = new MyWorker;
            
            QThread workerThread;
            workerThread.start();
            
            worker->moveToThread(&workerThread);
            QMetaObject::invokeMethod(worker, &MyWorker::initSocket, Qt::QueuedConnection);
            

            @J.Hilk said in QML multithread client with c++ integration:

            To avoid problems and conflicts, refrain from stack variables

            Just no! Stack is harder, better, faster, stronger. ;)

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #11

            @kshegunov said in QML multithread client with c++ integration:

            @J.Hilk said in QML multithread client with c++ integration:

            To avoid problems and conflicts, refrain from stack variables

            Just no! Stack is harder, better, faster, stronger. ;)

            In 99.99% of all cases I would say yes, it's true. ;-)

            But especially with QThreads I have 3 main reasons why I said that

            • (Allowed) stack size for non main threads can be (default) very limited. IIRC for MacOS is 100k
            • Many Qt classes do internal heap allocation anyway, making a stack declaration kind of moot.
            • Have you tried to do anything with a QTimer that is on the stack of a thread moved class ? Good luck with that

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            kshegunovK 1 Reply Last reply
            1
            • P Offline
              P Offline
              PouryaTorabi
              wrote on last edited by PouryaTorabi
              #12

              Thanks to you all, now it's working.
              First of all as you guys mentioned I can't move the socket to a new thread and should create the socket in the thread I want so I created an initSocket() function.
              To use the socket, as @LeLev said from another thread I should use the signal/slot, and it works correctly now.

              1 Reply Last reply
              1
              • J.HilkJ J.Hilk

                @kshegunov said in QML multithread client with c++ integration:

                @J.Hilk said in QML multithread client with c++ integration:

                To avoid problems and conflicts, refrain from stack variables

                Just no! Stack is harder, better, faster, stronger. ;)

                In 99.99% of all cases I would say yes, it's true. ;-)

                But especially with QThreads I have 3 main reasons why I said that

                • (Allowed) stack size for non main threads can be (default) very limited. IIRC for MacOS is 100k
                • Many Qt classes do internal heap allocation anyway, making a stack declaration kind of moot.
                • Have you tried to do anything with a QTimer that is on the stack of a thread moved class ? Good luck with that
                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by kshegunov
                #13

                @J.Hilk said in QML multithread client with c++ integration:

                But especially with QThreads I have 3 main reasons why I said that

                • (Allowed) stack size for non main threads can be (default) very limited. IIRC for MacOS is 100k

                Half a megabyte, which is more than enough. Even 100k is large enough. Realistically no library will create a thread stack by default with less than 256k from what I've observed, but even that number is quite enough for normal work.

                • Many Qt classes do internal heap allocation anyway, making a stack declaration kind of moot.

                Actually that's one very good reason to use it. You don't want to allocate a pointer in the heap, that's such a waste (also time-wise, the stack's much, much faster). Firstly your heap is getting fragmented, and secondly would you ordinarily do:

                int * a = new int;
                *a = 20;
                

                I wouldn't think so.

                • Have you tried to do anything with a QTimer that is on the stack of a thread moved class?

                Actually, I have. There's no problem with it, just give it the proper parent.

                PS. An important note
                While I and many others use "stack" as kind of a jargon, what formally is meant is "auto-storage". Bear in mind your worker object is allocated in the heap, so a member of it is not really allocated in the stack. This:

                struct A
                {
                    QByteArray x;
                };
                
                A * object = new A;
                

                Doesn't mean x is in the stack, it's still in the heap, however as you know the size of the QByteArray (and thus the full size of the structure) the heap allocation is done in one step as it'd been done on the stack. This is formally known as "auto-storage", but again, by merits of jargon we call it a "stack" allocation.

                Read and abide by the Qt Code of Conduct

                J.HilkJ 1 Reply Last reply
                1
                • kshegunovK kshegunov

                  @J.Hilk said in QML multithread client with c++ integration:

                  But especially with QThreads I have 3 main reasons why I said that

                  • (Allowed) stack size for non main threads can be (default) very limited. IIRC for MacOS is 100k

                  Half a megabyte, which is more than enough. Even 100k is large enough. Realistically no library will create a thread stack by default with less than 256k from what I've observed, but even that number is quite enough for normal work.

                  • Many Qt classes do internal heap allocation anyway, making a stack declaration kind of moot.

                  Actually that's one very good reason to use it. You don't want to allocate a pointer in the heap, that's such a waste (also time-wise, the stack's much, much faster). Firstly your heap is getting fragmented, and secondly would you ordinarily do:

                  int * a = new int;
                  *a = 20;
                  

                  I wouldn't think so.

                  • Have you tried to do anything with a QTimer that is on the stack of a thread moved class?

                  Actually, I have. There's no problem with it, just give it the proper parent.

                  PS. An important note
                  While I and many others use "stack" as kind of a jargon, what formally is meant is "auto-storage". Bear in mind your worker object is allocated in the heap, so a member of it is not really allocated in the stack. This:

                  struct A
                  {
                      QByteArray x;
                  };
                  
                  A * object = new A;
                  

                  Doesn't mean x is in the stack, it's still in the heap, however as you know the size of the QByteArray (and thus the full size of the structure) the heap allocation is done in one step as it'd been done on the stack. This is formally known as "auto-storage", but again, by merits of jargon we call it a "stack" allocation.

                  J.HilkJ Offline
                  J.HilkJ Offline
                  J.Hilk
                  Moderators
                  wrote on last edited by
                  #14

                  @kshegunov said in QML multithread client with c++ integration:

                  Actually, I have. There's no problem with it, just give it the proper parent.

                  Can you elaborate on that, when I try that I get a call to deleted constructor error.


                  Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                  Q: What's that?
                  A: It's blue light.
                  Q: What does it do?
                  A: It turns blue.

                  kshegunovK 1 Reply Last reply
                  0
                  • J.HilkJ J.Hilk

                    @kshegunov said in QML multithread client with c++ integration:

                    Actually, I have. There's no problem with it, just give it the proper parent.

                    Can you elaborate on that, when I try that I get a call to deleted constructor error.

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #15
                    class Worker : public QObject
                    {
                        Q_OBJECT
                    public:
                        Worker();
                    
                    private:
                        QTimer timer;
                    };
                    
                    Worker::Worker()
                        : timer(this)
                    {
                    }
                    

                    Read and abide by the Qt Code of Conduct

                    J.HilkJ 1 Reply Last reply
                    1
                    • kshegunovK kshegunov
                      class Worker : public QObject
                      {
                          Q_OBJECT
                      public:
                          Worker();
                      
                      private:
                          QTimer timer;
                      };
                      
                      Worker::Worker()
                          : timer(this)
                      {
                      }
                      
                      J.HilkJ Offline
                      J.HilkJ Offline
                      J.Hilk
                      Moderators
                      wrote on last edited by
                      #16

                      @kshegunov oh initializerlist, not my go do method.

                      Ok that works,
                      but I still get QObject::startTimer: Timers cannot be started from another thread errors when calling

                      void startTimer()
                      {
                          m_timer.start(1000);
                      }
                      

                      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                      Q: What's that?
                      A: It's blue light.
                      Q: What does it do?
                      A: It turns blue.

                      kshegunovK 1 Reply Last reply
                      0
                      • J.HilkJ J.Hilk

                        @kshegunov oh initializerlist, not my go do method.

                        Ok that works,
                        but I still get QObject::startTimer: Timers cannot be started from another thread errors when calling

                        void startTimer()
                        {
                            m_timer.start(1000);
                        }
                        
                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #17

                        Well, the message is descriptive. Don't start the timer from the wrong thread. ;)

                        Either start the timer before moving it to the other thread, or queue the call over the event loop of the receiving thread.

                        Read and abide by the Qt Code of Conduct

                        J.HilkJ 1 Reply Last reply
                        2
                        • kshegunovK kshegunov

                          Well, the message is descriptive. Don't start the timer from the wrong thread. ;)

                          Either start the timer before moving it to the other thread, or queue the call over the event loop of the receiving thread.

                          J.HilkJ Offline
                          J.HilkJ Offline
                          J.Hilk
                          Moderators
                          wrote on last edited by
                          #18

                          @kshegunov
                          well Kudos to you!
                          Something more to be learned from this thread ;-)


                          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                          Q: What's that?
                          A: It's blue light.
                          Q: What does it do?
                          A: It turns blue.

                          1 Reply Last reply
                          1

                          • Login

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