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. Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection
Forum Updated to NodeBB v4.3 + New Features

Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 644 Views 3 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.
  • CJhaC Offline
    CJhaC Offline
    CJha
    wrote on last edited by CJha
    #1

    Hi, I am using worker threads to do some calculations. In my main GUI thread, I have a function that is called to invoke a slot in a worker thread. The worker thread then invokes multiple slots in subworker threads. The entire process is something like this:

    Master GUI Thread (subclass of QWidget)

    void Master::startWorker()
    {
        QMetaObject::invokeMethod(workerObject, "startWorking", Qt::QueuedConnection, Q_ARG(double, wid), Q_ARG(double, hit));
    }
    

    Worker Object (subclass of QObject)

    void Worker::startWorking(double wid, double hit)
    {
        for(int ii = 0; ii < subWorkerCount; ++ii) {
            QMetaObject::invokeMethod(subWorkerObject[ii], "startSubWorking", Qt::QueuedConnection, Q_ARG(double, wid), Q_ARG(double, hit));
        }
    }
    

    SubWorker Object (subclass of QObject)

    void SubWorker::startSubWorking(double wid, double hit)
    {
        // Does the calculation: total time ~15 ms
    }
    

    All the worker and subworkers have their own threads and I use moveToThread() to move these QObject subclasses to their respective QThread and then I start the thread.

    The function void Master::startWorker() is called during the paintEvent() of the QWidget. If I do not call this function during the paintEvent() then the total time taken by the paintEvent() is less than 20 ms. But, if I call this function then the total time taken by paint event is around 170 ms. Why is this the case? I thought using Qt::QueuedConnection would mean that my main GUI thread will not stop, also I tried the with Qt::AutoConnection everywhere and the results were the same.

    kshegunovK 1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Why do you use QMetaObject::invokeMethod() instead simple signal/slot connections? Then you don't need to worry about Queued/Direct connections at all.

      When the gui thread freezes you do something wrong. But without a simple reproducer we can't tell why. Output the current thread id to see in which thread the operations are done.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      CJhaC 1 Reply Last reply
      0
      • Christian EhrlicherC Christian Ehrlicher

        Why do you use QMetaObject::invokeMethod() instead simple signal/slot connections? Then you don't need to worry about Queued/Direct connections at all.

        When the gui thread freezes you do something wrong. But without a simple reproducer we can't tell why. Output the current thread id to see in which thread the operations are done.

        CJhaC Offline
        CJhaC Offline
        CJha
        wrote on last edited by
        #3

        @Christian-Ehrlicher said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

        Why do you use QMetaObject::invokeMethod() instead simple signal/slot connections? Then you don't need to worry about Queued/Direct connections at all.

        This is because in my application the Worker and SubWorker objects are created dynamically and I need to pass valuess to them in a slot so that they can start working. Qt doesn't allow me to create vectors of signals and so I need to use QMetaObject::invokeMethod() function.

        When the gui thread freezes you do something wrong. But without a simple reproducer we can't tell why. Output the current thread id to see in which thread the operations are done.

        I did that, all the SubWorker threads are done before the GUI thread is done. It seems the GUI thread just stops till the worker threads are done. The function void Master::startWorker() is the only way I invoke the slot in my Worker object during the entire update process. I am new to multi-threading and so I thought maybe I am missing something simple, I will make a small reproducible code and share it here.

        1 Reply Last reply
        0
        • CJhaC CJha

          Hi, I am using worker threads to do some calculations. In my main GUI thread, I have a function that is called to invoke a slot in a worker thread. The worker thread then invokes multiple slots in subworker threads. The entire process is something like this:

          Master GUI Thread (subclass of QWidget)

          void Master::startWorker()
          {
              QMetaObject::invokeMethod(workerObject, "startWorking", Qt::QueuedConnection, Q_ARG(double, wid), Q_ARG(double, hit));
          }
          

          Worker Object (subclass of QObject)

          void Worker::startWorking(double wid, double hit)
          {
              for(int ii = 0; ii < subWorkerCount; ++ii) {
                  QMetaObject::invokeMethod(subWorkerObject[ii], "startSubWorking", Qt::QueuedConnection, Q_ARG(double, wid), Q_ARG(double, hit));
              }
          }
          

          SubWorker Object (subclass of QObject)

          void SubWorker::startSubWorking(double wid, double hit)
          {
              // Does the calculation: total time ~15 ms
          }
          

          All the worker and subworkers have their own threads and I use moveToThread() to move these QObject subclasses to their respective QThread and then I start the thread.

          The function void Master::startWorker() is called during the paintEvent() of the QWidget. If I do not call this function during the paintEvent() then the total time taken by the paintEvent() is less than 20 ms. But, if I call this function then the total time taken by paint event is around 170 ms. Why is this the case? I thought using Qt::QueuedConnection would mean that my main GUI thread will not stop, also I tried the with Qt::AutoConnection everywhere and the results were the same.

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

          What @Christian-Ehrlicher said, and I specifically want to know the result of:

          void SubWorker::startSubWorking(double wid, double hit)
          {
              Q_ASSERT(thread() == QThread::currentThread());
              qDebug() << QThread::currentThread();
              // ...
          }
          

          coupled together with:

          void Worker::startWorking(double wid, double hit)
          {
              Q_ASSERT(thread() == QThread::currentThread());
              qDebug() << QThread::currentThread() << qApp->thread();
              // ...
          }
          

          Read and abide by the Qt Code of Conduct

          CJhaC 1 Reply Last reply
          2
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

            Qt doesn't allow me to create vectors of signals and so I need to use QMetaObject::invokeMethod() function.

            I don't see a difference...

            all the SubWorker threads are done before the GUI thread is done

            I asked you to print out thread thread id...

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            0
            • kshegunovK kshegunov

              What @Christian-Ehrlicher said, and I specifically want to know the result of:

              void SubWorker::startSubWorking(double wid, double hit)
              {
                  Q_ASSERT(thread() == QThread::currentThread());
                  qDebug() << QThread::currentThread();
                  // ...
              }
              

              coupled together with:

              void Worker::startWorking(double wid, double hit)
              {
                  Q_ASSERT(thread() == QThread::currentThread());
                  qDebug() << QThread::currentThread() << qApp->thread();
                  // ...
              }
              
              CJhaC Offline
              CJhaC Offline
              CJha
              wrote on last edited by
              #6

              @kshegunov Thanks!
              @kshegunov @Christian-Ehrlicher This is the result:

              Thread:  QThread(0x2858b65a0e0) 	qApp Thread:  QThread(0x2858614f570) // For Worker
              Thread:  QThread(0x2858b659960) // For SubWorker
              Thread:  QThread(0x2858b659cd0) // For SubWorker
              Thread:  QThread(0x2858b65a040) // For SubWorker
              Thread:  QThread(0x2858b65a270) // For SubWorker
              Thread:  QThread(0x2858b659c30) // For SubWorker
              Thread:  QThread(0x2858b65a4f0) // For SubWorker
              Thread:  QThread(0x2858b659ff0) // For SubWorker
              Thread:  QThread(0x2858b659d20) // For SubWorker
              Thread:  QThread(0x2858b659f50) // For SubWorker
              Thread:  QThread(0x2858b659c80) // For SubWorker
              
              

              I don't see a difference...

              My Worker objects are created during run time, their numbers can vary. I need to pass data through the startWorking()slot to my worker (so that the connection is queued and the startWorking() is executed in the worker's thread). For each worker the data that is passed is different, this means that I need a unique signal in my master for each worker's startWorking() slot. If I use the same signal from my master then each time I will send a data it will be received by all the workers and not only to the one it is intended for. Since workers are created dynamically during run-time and signals cannot be created at run-time (as far as I know), I cannot use signals/slots to do this communication and so I am stuck with QMetaObject::invokeMethod().

              kshegunovK 1 Reply Last reply
              0
              • CJhaC CJha

                @kshegunov Thanks!
                @kshegunov @Christian-Ehrlicher This is the result:

                Thread:  QThread(0x2858b65a0e0) 	qApp Thread:  QThread(0x2858614f570) // For Worker
                Thread:  QThread(0x2858b659960) // For SubWorker
                Thread:  QThread(0x2858b659cd0) // For SubWorker
                Thread:  QThread(0x2858b65a040) // For SubWorker
                Thread:  QThread(0x2858b65a270) // For SubWorker
                Thread:  QThread(0x2858b659c30) // For SubWorker
                Thread:  QThread(0x2858b65a4f0) // For SubWorker
                Thread:  QThread(0x2858b659ff0) // For SubWorker
                Thread:  QThread(0x2858b659d20) // For SubWorker
                Thread:  QThread(0x2858b659f50) // For SubWorker
                Thread:  QThread(0x2858b659c80) // For SubWorker
                
                

                I don't see a difference...

                My Worker objects are created during run time, their numbers can vary. I need to pass data through the startWorking()slot to my worker (so that the connection is queued and the startWorking() is executed in the worker's thread). For each worker the data that is passed is different, this means that I need a unique signal in my master for each worker's startWorking() slot. If I use the same signal from my master then each time I will send a data it will be received by all the workers and not only to the one it is intended for. Since workers are created dynamically during run-time and signals cannot be created at run-time (as far as I know), I cannot use signals/slots to do this communication and so I am stuck with QMetaObject::invokeMethod().

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

                Seems correct. As for your reasoning, it does appear to me your work type succumbs best to pooling the threads and running the calculation as jobs. Like QtConcurrent::run or alike.

                Read and abide by the Qt Code of Conduct

                CJhaC 1 Reply Last reply
                1
                • kshegunovK kshegunov

                  Seems correct. As for your reasoning, it does appear to me your work type succumbs best to pooling the threads and running the calculation as jobs. Like QtConcurrent::run or alike.

                  CJhaC Offline
                  CJhaC Offline
                  CJha
                  wrote on last edited by
                  #8

                  @kshegunov Thanks! Yeah, I tried QtConcurrent::run as well first. The problem with QtConcurrent::run is that it doesn't allow me to change the priority of the thread pool (there are some workarounds but I am not really convinced). And I really need to have a thread priority system as I have to deal with high-frequency data generated with data acquisition systems (DAQs) using these classes. I could not find any other proper solution so I decided to make my own using QThread. If you have any references, I would be happy to know :)

                  kshegunovK 1 Reply Last reply
                  0
                  • CJhaC CJha

                    @kshegunov Thanks! Yeah, I tried QtConcurrent::run as well first. The problem with QtConcurrent::run is that it doesn't allow me to change the priority of the thread pool (there are some workarounds but I am not really convinced). And I really need to have a thread priority system as I have to deal with high-frequency data generated with data acquisition systems (DAQs) using these classes. I could not find any other proper solution so I decided to make my own using QThread. If you have any references, I would be happy to know :)

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

                    @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                    The problem with QtConcurrent::run is that it doesn't allow me to change the priority of the thread pool (there are some workarounds but I am not really convinced).

                    You shouldn't need to. Changing the thread priority won't give you any performance as such.

                    @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                    And I really need to have a thread priority system as I have to deal with high-frequency data generated with data acquisition systems (DAQs) using these classes.

                    If you want to enforce the latency constraint, then you should go low-level with a producer-consumer queue, not rely on the mutex of the signal-slot mechanism, much less resolve the slot calls at runtime (i.e. invokeMethod with a string argument). Search the forums I've written at least 2-3 posts how a TS queue can be straightforwardly implemented. After you get that, derive from QThread override run and put your calculations there dropping the worker object altogether.

                    Note: When spinning the worker threads you want to use exactly QThread::idealThreadCount not more, not less. Switching between threads can be really costly.

                    Read and abide by the Qt Code of Conduct

                    CJhaC 1 Reply Last reply
                    2
                    • kshegunovK kshegunov

                      @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                      The problem with QtConcurrent::run is that it doesn't allow me to change the priority of the thread pool (there are some workarounds but I am not really convinced).

                      You shouldn't need to. Changing the thread priority won't give you any performance as such.

                      @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                      And I really need to have a thread priority system as I have to deal with high-frequency data generated with data acquisition systems (DAQs) using these classes.

                      If you want to enforce the latency constraint, then you should go low-level with a producer-consumer queue, not rely on the mutex of the signal-slot mechanism, much less resolve the slot calls at runtime (i.e. invokeMethod with a string argument). Search the forums I've written at least 2-3 posts how a TS queue can be straightforwardly implemented. After you get that, derive from QThread override run and put your calculations there dropping the worker object altogether.

                      Note: When spinning the worker threads you want to use exactly QThread::idealThreadCount not more, not less. Switching between threads can be really costly.

                      CJhaC Offline
                      CJhaC Offline
                      CJha
                      wrote on last edited by
                      #10

                      @kshegunov said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                      You shouldn't need to. Changing the thread priority won't give you any performance as such.

                      I thought if I put the priority as QThread::LowPriority for one instance and QThread::HighPriority for the other then Qt will make sure that one with higher priority gets the resources whenever it requires regardless of how long the threads with lower priority are waiting? If this is not the situation then why do we have different priorities in the first place?

                      If you want to enforce the latency constraint, then you should go low-level with a producer-consumer queue, not rely on the mutex of the signal-slot mechanism, much less resolve the slot calls at runtime (i.e. invokeMethod with a string argument). Search the forums I've written at least 2-3 posts how a TS queue can be straightforwardly implemented. After you get that, derive from QThread override run and put your calculations there dropping the worker object altogether.

                      Note: When spinning the worker threads you want to use exactly QThread::idealThreadCount not more, not less. Switching between threads can be really costly.

                      Most of the people on forums and blogs suggest subclassing QObject and use moveToThread() instead of subclassing QThread and implementing its run method, why do you suggest differently? Is there a catch?
                      Never heard of TS queue, I will try to learn about it. Thanks for the help :)

                      kshegunovK 1 Reply Last reply
                      0
                      • CJhaC CJha

                        @kshegunov said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                        You shouldn't need to. Changing the thread priority won't give you any performance as such.

                        I thought if I put the priority as QThread::LowPriority for one instance and QThread::HighPriority for the other then Qt will make sure that one with higher priority gets the resources whenever it requires regardless of how long the threads with lower priority are waiting? If this is not the situation then why do we have different priorities in the first place?

                        If you want to enforce the latency constraint, then you should go low-level with a producer-consumer queue, not rely on the mutex of the signal-slot mechanism, much less resolve the slot calls at runtime (i.e. invokeMethod with a string argument). Search the forums I've written at least 2-3 posts how a TS queue can be straightforwardly implemented. After you get that, derive from QThread override run and put your calculations there dropping the worker object altogether.

                        Note: When spinning the worker threads you want to use exactly QThread::idealThreadCount not more, not less. Switching between threads can be really costly.

                        Most of the people on forums and blogs suggest subclassing QObject and use moveToThread() instead of subclassing QThread and implementing its run method, why do you suggest differently? Is there a catch?
                        Never heard of TS queue, I will try to learn about it. Thanks for the help :)

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

                        @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                        I thought if I put the priority as QThread::LowPriority for one instance and QThread::HighPriority for the other then Qt will make sure that one with higher priority gets the resources whenever it requires regardless of how long the threads with lower priority are waiting? If this is not the situation then why do we have different priorities in the first place?

                        This is not Qt-specific. On a multitasking system the priority of process or thread determines the timeslices it gets from the OS's scheduler. However, there are so many cores on a system, you can't get performance out of nothing. That's why if you're going to crunch numbers, you want to have a number of threads equal to the number of cores, so each thread runs on its own core as much of the time as possible without being interrupted. Having more threads than cores, contrary to (the layman) popular belief, doesn't produce better performance, it can get you some latency benefit if the cores are not busy, otherwise it's an overhead for the scheduler to slice and rebalance the time slots. That's why you have priorities - to "hijack" latency from other threads/processes running on that system, but again this doesn't mean your code is going to be running faster.

                        @CJha said in Main GUI thread stops when worker thread is invoked using Qt::QueuedConnection:

                        Most of the people on forums and blogs suggest subclassing QObject and use moveToThread() instead of subclassing QThread and implementing its run method, why do you suggest differently? Is there a catch?

                        Yes, that's correct. For the general case this is best. If you want to squeeze out the most of the hardware however you're going to want to remove the pesky overhead that comes with this. That's "the catch" - having/choosing the correct tool for the job at hand.

                        Never heard of TS queue, I will try to learn about it.

                        That's a "thread-safe queue" so you don't get the wrong idea.

                        Read and abide by the Qt Code of Conduct

                        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