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. QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever
Forum Updated to NodeBB v4.3 + New Features

QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 4 Posters 5.1k 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
    sykac
    wrote on last edited by
    #1

    Hello,

    In my application I have a main thread and a worker thread (done with moveToThread). The woker thread runs in a loop which collects some data. What I want to do is to call a getter for this woker data from the main thread. So I called it like this:

    qRegisterMetaType<Data>("Data");
    Data d;
    QMetaObject::invokeMethod(worker_, "getData", Qt::BlockingQueuedConnection,
                              Q_RETURN_ARG(Data, d),
                              Q_ARG(QString,   arg));
    

    Where Data getData(QString arg) is a public slot in the worker object.

    The problem is that this hangs forever (not sure if forever but a minute is already enough, I need it immediately). Calling it with DirectConnection makes it execute in the main thraed which I don't want to. So what is the problem here? It never reaches the getData() method. Is there something else which I could use for such an asynchronous data polling?

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      does the worker thread run an event loop? if so, are you blocking it with an infinite loop?

      Looks like the invokeMethod never gets picked up by the worker loop

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

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

        The main thread started with

        QCoreApplication a(argc, argv);
        return a.exec();
        

        and in the main thread the worker was started with

        worker->moveToThread(thread);
        thread->start();
        

        Then the worker starts the infinite loop, yes. I thought that this is somehow handled by Qt, so that the worker's methods can be invoked although it's running in a loop. But probably I was wrong, or was I?

        VRoninV kshegunovK 2 Replies Last reply
        0
        • S sykac

          The main thread started with

          QCoreApplication a(argc, argv);
          return a.exec();
          

          and in the main thread the worker was started with

          worker->moveToThread(thread);
          thread->start();
          

          Then the worker starts the infinite loop, yes. I thought that this is somehow handled by Qt, so that the worker's methods can be invoked although it's running in a loop. But probably I was wrong, or was I?

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @sykac said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

          Then the worker starts the infinite loop

          Usually this is not necessary but yes, yhis is the cause of your invoke not working

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          0
          • KillerSmathK Offline
            KillerSmathK Offline
            KillerSmath
            wrote on last edited by KillerSmath
            #5

            @sykac
            Hi there, i am not expert with QThread but have you tried to use a request and response signals to invoke and receive the data from your worker thread to main thread ?

            Obs: I don't know if this is the best way to request data from thread.

            @Computer Science Student - Brazil
            Web Developer and Researcher
            “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

            VRoninV 1 Reply Last reply
            0
            • S sykac

              The main thread started with

              QCoreApplication a(argc, argv);
              return a.exec();
              

              and in the main thread the worker was started with

              worker->moveToThread(thread);
              thread->start();
              

              Then the worker starts the infinite loop, yes. I thought that this is somehow handled by Qt, so that the worker's methods can be invoked although it's running in a loop. But probably I was wrong, or was I?

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

              @sykac said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

              Then the worker starts the infinite loop, yes.

              What infinite loop, can you show us?
              If you block the event loop then that means you can't process queued events, thus your call with BlockingQueuedConnection will just hang there until the actual event posted in the event queue is processed.

              @KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

              Obs: I don't know if this is the best way to request data from thread.

              It is, indeed.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              2
              • KillerSmathK Offline
                KillerSmathK Offline
                KillerSmath
                wrote on last edited by KillerSmath
                #7

                @kshegunov
                Okay, i told it because i readed some topics about send data using signals and noticed that it's not recommended to send data in signals because they makes a copy of data to send as parameter and another copy is made at slot, and make copy can takes time depending of data size.

                @Computer Science Student - Brazil
                Web Developer and Researcher
                “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                kshegunovK 1 Reply Last reply
                0
                • KillerSmathK KillerSmath

                  @kshegunov
                  Okay, i told it because i readed some topics about send data using signals and noticed that it's not recommended to send data in signals because they makes a copy of data to send as parameter and another copy is made at slot, and make copy can takes time depending of data size.

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

                  That's why Qt leverages implicit sharing to begin with. When you have the case that the signal/slot parameter(s) have to copy big-ish data chunks, then it's time to use QSharedData and QSharedDataPointer. This way you get the shallowest copies possible - i.e. a pointer being copied, and whenever you have a write operation the data would detach if it's shared.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  2
                  • KillerSmathK KillerSmath

                    @sykac
                    Hi there, i am not expert with QThread but have you tried to use a request and response signals to invoke and receive the data from your worker thread to main thread ?

                    Obs: I don't know if this is the best way to request data from thread.

                    VRoninV Offline
                    VRoninV Offline
                    VRonin
                    wrote on last edited by
                    #9

                    @KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                    use a request and response signals to invoke and receive the data from your worker thread to main thread ?

                    Even this solution requires a non-blocked event loop running on the worker-thread side

                    @kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                    whenever you have a write operation the data would detach if it's shared.

                    Worth mentioning in this context that it is thread safe as long as const means thread safe or you use QExplicitlySharedDataPointer to make thread safe.

                    I'm not that knowledgeable of Qt internals to assure you but I'd guess most if not all the Qt classes are usable without thinking about copying

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    kshegunovK 1 Reply Last reply
                    0
                    • VRoninV VRonin

                      @KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                      use a request and response signals to invoke and receive the data from your worker thread to main thread ?

                      Even this solution requires a non-blocked event loop running on the worker-thread side

                      @kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                      whenever you have a write operation the data would detach if it's shared.

                      Worth mentioning in this context that it is thread safe as long as const means thread safe or you use QExplicitlySharedDataPointer to make thread safe.

                      I'm not that knowledgeable of Qt internals to assure you but I'd guess most if not all the Qt classes are usable without thinking about copying

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

                      @VRonin said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                      Worth mentioning in this context that it is thread safe as long as const means thread safe or you use QExplicitlySharedDataPointer to make thread safe.

                      Eh, what? I did not at all mention thread safety. But in any case so we clear the issue here - no, the data is not thread-safe. The only thing that is thread-safe (sort of) in the whole scheme is the data copying, which happens behind the scenes. And this is just so you can delay the actual copy as long as possible, and to ensure that your objects behave correctly when it comes to reentrancy (if you have statics the object will still not be reentrant). This in no way guards the actual data from concurrent access! (bold!)

                      Read and abide by the Qt Code of Conduct

                      VRoninV 1 Reply Last reply
                      1
                      • S Offline
                        S Offline
                        sykac
                        wrote on last edited by sykac
                        #11

                        Thanks for suggestions guys.

                        @kshegunov My infinite loop is while(flag) doStuff();, so it's definitely because of it. So if doStuff() was connected to a timer and wasn't in the while loop, it would work?

                        But I'll probably stick with the object in the main thread simply calling the method of the worker which will be executed in the main thread. And as you're mentioning thread safety and data manipulation - is this safe?

                        kshegunovK 1 Reply Last reply
                        0
                        • kshegunovK kshegunov

                          @VRonin said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                          Worth mentioning in this context that it is thread safe as long as const means thread safe or you use QExplicitlySharedDataPointer to make thread safe.

                          Eh, what? I did not at all mention thread safety. But in any case so we clear the issue here - no, the data is not thread-safe. The only thing that is thread-safe (sort of) in the whole scheme is the data copying, which happens behind the scenes. And this is just so you can delay the actual copy as long as possible, and to ensure that your objects behave correctly when it comes to reentrancy (if you have statics the object will still not be reentrant). This in no way guards the actual data from concurrent access! (bold!)

                          VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on last edited by
                          #12

                          @kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                          I did not at all mention thread safety.

                          I know, I just brought it up as this thread was about multithreading

                          @kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                          This in no way guards the actual data from concurrent access!

                          What I meant is that if type T is reentrant, using QSharedData does not break reentrancy as both the reference counter and detach() are thread safe.
                          If you have const methods that actually change the internal state then you still have a race condition (as in this case const != thread safe)

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          1 Reply Last reply
                          2
                          • KillerSmathK Offline
                            KillerSmathK Offline
                            KillerSmath
                            wrote on last edited by
                            #13

                            @sykac

                            Remember, it is not a good practice to use an infinite loop in a thread, but you can solve your problem usingprocessEventsinside your loop to force your worker to process the events.

                            Below is an example of how you can implement:

                            worker.h

                            #ifndef WORKER_H
                            #define WORKER_H
                            
                            #include <QObject>
                            #include <QMutex>
                            
                            class Worker : public QObject
                            {
                                Q_OBJECT
                            public:
                                explicit Worker(QObject *parent = nullptr);
                                ~Worker();
                            
                            signals:
                                // get data using signals
                                void requestData();
                                void responseData(const int number);
                                
                                void finished();
                            
                            public slots:
                                void process();
                                void stop();
                                int getData();
                            
                            private:
                                QMutex m_mutex;
                                bool m_stop;
                                int m_data;
                            
                                void doStuff();
                            };
                            
                            #endif // WORKER_H
                            

                            worker.cpp

                            #include "worker.h"
                            #include <QCoreApplication>
                            //#include <QMutexLocker>
                            
                            Worker::Worker(QObject *parent) : QObject(parent)
                            {
                                m_data = 0;
                                m_stop = false;
                            
                                connect(this, &Worker::requestData, this, [this](){ // if prefer to use signals to return data
                                    // checksum or processing the data
                                    // ...
                                    // ...
                                    // done checksum or processing
                                    emit responseData(m_data);
                                });
                            }
                            
                            Worker::~Worker(){
                            //    m_mutex.lock();
                            //    if(!m_stop)
                            //        m_stop = true;
                                //    m_mutex.unlock();
                            }
                            
                            int Worker::getData()
                            {
                                return m_data;
                            }
                            
                            void Worker::stop(){
                                m_mutex.lock();
                                if(!m_stop)
                                    m_stop = true;
                                m_mutex.unlock();
                            }
                            
                            void Worker::process()
                            {
                                m_stop = false;
                            
                                while(!m_stop)
                                {
                                    doStuff();
                                    QCoreApplication::processEvents(QEventLoop::AllEvents); // force the process of events among each iteration
                                }
                            
                                emit finished();
                            }
                            
                            void Worker::doStuff()
                            {
                                // QMutexLocker locker(&m_mutex); // if necessary for security
                                m_data = (m_data + 1) % 101;
                            }
                            

                            your_application constructor

                            ...
                                newThread = new QThread();
                                newWorker = new Worker();
                                newWorker->moveToThread(newThread);
                                
                                connect(newThread, &QThread::started, newWorker, &Worker::process);
                                connect(newWorker, &Worker::finished, newWorker, &Worker::deleteLater);
                             
                                newThread->start();
                            
                               // using signals to request and response data
                            
                                connect(newWorker, &Worker::responseData, [this](const int data){
                                    qDebug() << "Data Received:" << data;
                                });
                            
                                QTimer::singleShot(5000, newWorker, &Worker::requestData);
                            
                                // or calling method from worker to return data
                            
                               int d;
                               QMetaObject::invokeMethod(newWorker, "getData", Qt::BlockingQueuedConnection,
                                                          Q_RETURN_ARG(int, d));
                            
                               qDebug() << d;
                            
                               
                            ...
                            

                            your_application destructor

                            ...
                                newWorker->stop();
                            
                                newThread->quit();
                                newThread->wait();
                                
                                delete newThread;
                            ...
                            

                            @Computer Science Student - Brazil
                            Web Developer and Researcher
                            “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

                            1 Reply Last reply
                            0
                            • S sykac

                              Thanks for suggestions guys.

                              @kshegunov My infinite loop is while(flag) doStuff();, so it's definitely because of it. So if doStuff() was connected to a timer and wasn't in the while loop, it would work?

                              But I'll probably stick with the object in the main thread simply calling the method of the worker which will be executed in the main thread. And as you're mentioning thread safety and data manipulation - is this safe?

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

                              @sykac said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                              So if doStuff() was connected to a timer and wasn't in the while loop, it would work?

                              Yes.

                              And as you're mentioning thread safety and data manipulation - is this safe?

                              Is what safe? If you use the data from one thread only then it's safe, yes.

                              @KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:

                              Below is an example of how you can implement

                              Is the mutex really necessary to guard a simple boolean? I'd suggest substituting that with an atomic, even if Qt's mutex implementation is rather fast.

                              Read and abide by the Qt Code of Conduct

                              1 Reply Last reply
                              2

                              • Login

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