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. Own thread for each QQuickWidget

Own thread for each QQuickWidget

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 3 Posters 748 Views 1 Watching
  • 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
    stewo
    wrote on last edited by
    #1

    Hi,

    we are porting a rather big embedded application from Qt4 to Qt5. To benefit from the new features of Qt Quick, we decided to reimplement some dialogs in QML by using QQuickWidgets. Now we have realized that there seems to be an own thread for each QQuickWidget. Because each threads needs its own stack, this cost much memory.

    Does anyone have some information about QQuickWidgets and their threads? I could not find anything in the documentation. Is there a way to change this behavior?

    Best regards,
    stewo

    raven-worxR 1 Reply Last reply
    0
    • S Offline
      S Offline
      stewo
      wrote on last edited by stewo
      #4

      I have heard about the only one GUI thread topic, but /proc/pid/status shows me a very high number of threads and it increases with each created QQuickWidget. Together with the VmSize. I think those threads are no GUI threads, but perhaps for some interactions between Qt Quick and Qt Widget. Perhaps for the Qml Context or Engine?

      Here is some code to reproduce this behavior. Works for me on our embedded target and in Ubuntu.

      
      void MainWindow::on_pushButton_clicked()
      {
        QQuickWidget* quickWidget = new QQuickWidget(this);
        quickWidget->setSource(QUrl("qrc:/RedRectangle.qml"));
        quickWidget->show();
      
        QProcess process;
        process.start("cat", QStringList() << QString("/proc/%1/status").arg(QCoreApplication::applicationPid()));
        process.waitForFinished();
      
        QString output = process.readAll();
        qDebug() << "Number of threads:" << output.split("Threads").at(1).split("\n").at(0).mid(2);
        qDebug() << "VmSize:" << output.split("VmSize").at(1).split("\n").at(0).mid(4);
      
        process.close();
      }
      

      And here the output of this code:

      Number of threads: "7"
      VmSize: "175096 kB"
      Number of threads: "8"
      VmSize: "197020 kB"
      Number of threads: "9"
      VmSize: "217928 kB"
      Number of threads: "10"
      VmSize: "238832 kB"
      

      Edit:
      I added the VmSize. Each QQuickWidgets reserves about 20 MB of RAM. 8 MB of those are for the stack.

      Edit:
      I looked into the documentation of QQuickWidget and saw that there is a constructor which needs a QQmlEngine. When creating a global engine-object and using this for the QQuickWidgets there are no additional threads and just a bit additional memory usage. I will try to create a global engine and use local contexts for each QQuickWidget in our application. If the application will work as before, this could reduce the memory usage drastically.

      Edit:
      I finally found a solution. The problem was to find a way to pass an own QQmlContext to a QQuickWidget, but use the same QQmlEngine at the same time. I had to take the indirection over the QQmlComponent. Here is some code:

        QQmlEngine*   engine = new QQmlEngine();
        QQmlContext*  context = new QQmlContext(engine);
      
        engine->rootContext()->setContextProperty("message", "marco");
        context->setContextProperty("message", "polo");
      
        QQuickWidget* quickWidget = new QQuickWidget(engine, this);
        quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
        QQmlComponent* component = new QQmlComponent(engine, "qrc:/MarcoPolo.qml");
        quickWidget->setContent(component->url(), component, component->create(context));
        ui->verticalLayout->addWidget(quickWidget);
      

      This reduced the virtual memory usage and the number of threads drastically.

      Please tell me, if anyone has a simpler solution.

      1 Reply Last reply
      1
      • dheerendraD Offline
        dheerendraD Offline
        dheerendra
        Qt Champions 2022
        wrote on last edited by
        #2

        UI only in main thread and rest of the backend work can be in worker thread.

        Dheerendra
        @Community Service
        Certified Qt Specialist
        http://www.pthinks.com

        1 Reply Last reply
        0
        • S stewo

          Hi,

          we are porting a rather big embedded application from Qt4 to Qt5. To benefit from the new features of Qt Quick, we decided to reimplement some dialogs in QML by using QQuickWidgets. Now we have realized that there seems to be an own thread for each QQuickWidget. Because each threads needs its own stack, this cost much memory.

          Does anyone have some information about QQuickWidgets and their threads? I could not find anything in the documentation. Is there a way to change this behavior?

          Best regards,
          stewo

          raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by
          #3

          @stewo said in Own thread for each QQuickWidget:

          Now we have realized that there seems to be an own thread for each QQuickWidget

          how exactly did you get to that conclusion?

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          0
          • S Offline
            S Offline
            stewo
            wrote on last edited by stewo
            #4

            I have heard about the only one GUI thread topic, but /proc/pid/status shows me a very high number of threads and it increases with each created QQuickWidget. Together with the VmSize. I think those threads are no GUI threads, but perhaps for some interactions between Qt Quick and Qt Widget. Perhaps for the Qml Context or Engine?

            Here is some code to reproduce this behavior. Works for me on our embedded target and in Ubuntu.

            
            void MainWindow::on_pushButton_clicked()
            {
              QQuickWidget* quickWidget = new QQuickWidget(this);
              quickWidget->setSource(QUrl("qrc:/RedRectangle.qml"));
              quickWidget->show();
            
              QProcess process;
              process.start("cat", QStringList() << QString("/proc/%1/status").arg(QCoreApplication::applicationPid()));
              process.waitForFinished();
            
              QString output = process.readAll();
              qDebug() << "Number of threads:" << output.split("Threads").at(1).split("\n").at(0).mid(2);
              qDebug() << "VmSize:" << output.split("VmSize").at(1).split("\n").at(0).mid(4);
            
              process.close();
            }
            

            And here the output of this code:

            Number of threads: "7"
            VmSize: "175096 kB"
            Number of threads: "8"
            VmSize: "197020 kB"
            Number of threads: "9"
            VmSize: "217928 kB"
            Number of threads: "10"
            VmSize: "238832 kB"
            

            Edit:
            I added the VmSize. Each QQuickWidgets reserves about 20 MB of RAM. 8 MB of those are for the stack.

            Edit:
            I looked into the documentation of QQuickWidget and saw that there is a constructor which needs a QQmlEngine. When creating a global engine-object and using this for the QQuickWidgets there are no additional threads and just a bit additional memory usage. I will try to create a global engine and use local contexts for each QQuickWidget in our application. If the application will work as before, this could reduce the memory usage drastically.

            Edit:
            I finally found a solution. The problem was to find a way to pass an own QQmlContext to a QQuickWidget, but use the same QQmlEngine at the same time. I had to take the indirection over the QQmlComponent. Here is some code:

              QQmlEngine*   engine = new QQmlEngine();
              QQmlContext*  context = new QQmlContext(engine);
            
              engine->rootContext()->setContextProperty("message", "marco");
              context->setContextProperty("message", "polo");
            
              QQuickWidget* quickWidget = new QQuickWidget(engine, this);
              quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
              QQmlComponent* component = new QQmlComponent(engine, "qrc:/MarcoPolo.qml");
              quickWidget->setContent(component->url(), component, component->create(context));
              ui->verticalLayout->addWidget(quickWidget);
            

            This reduced the virtual memory usage and the number of threads drastically.

            Please tell me, if anyone has a simpler solution.

            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