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. Wait for result from other thread

Wait for result from other thread

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 5 Posters 4.5k 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.
  • R Offline
    R Offline
    rdeem
    wrote on last edited by
    #1

    Hi,

    I have spent countless hours reading about QThreads, but I feel that I still miss some vital knowledge on QThreads and eventloops. Below is an example of requesting data from another thread and then wait for the result. For some reason this doesn't work and I was hoping someone could explain why. The queueAction signal is triggered from a button in QML.

    //Main
    Requester requester;
    Provider provider;
    QThread* requestThread = new QThread();
    QThread* provideThread = new QThread();
    QThread::currentThread()->setObjectName("MainThread");
    requestThread->setObjectName("RequestThread");
    provideThread->setObjectName("ProvideThread");
    requester.moveToThread(requestThread);
    provider.moveToThread(provideThread);
    QObject::connect(&requester, SIGNAL(requestData()), &provider, SLOT(handleRequest()));
    QObject::connect(&provider, SIGNAL(sendResult(int)), &requester, SLOT(receiveResult(int)));
    requestThread->start();
    provideThread->start();
    
    //Requester.h
    class Requester : public QObject
    {
        Q_OBJECT
    public:
        Requester() :
            loop()
        {
            connect(this, SIGNAL(wakeLoop()), &loop, SLOT(quit()));
            connect(this, SIGNAL(queueAction()), this, SLOT(action()),Qt::QueuedConnection);
        }
    
    signals:
        void wakeLoop();
        void queueAction();
        void requestData();
    
    public slots:
        void action() {
            qDebug() << "Sending request in thread" << thread()->currentThread()->objectName();
            emit requestData();
            loop.exec();
            qDebug() << "Finished waiting for result in thread" << thread()->currentThread()->objectName();
        }
    
        void receiveResult(int result) {
            qDebug() << "Received result" << result << "in thread" << thread()->currentThread()->objectName();
            emit wakeLoop();
        }
    
    private:
        QEventLoop loop;
    };
    
    //Provider.h
    class Provider : public QObject
    {
        Q_OBJECT
    public:
        Provider() {}
    
    signals:
        void sendResult(int result);
    
    public slots:
        void handleRequest()
        {
            qDebug() << "Received request in thread" << thread()->currentThread()->objectName();
            emit sendResult(2);
        }
    };
    

    The code above gives the following output:
    [D] Requester::action:27 - Sending request in thread "RequestThread"
    [D] Provider::handleRequest:20 - Received request in thread "ProvideThread"

    However If I keep Requester in main thread instead of moving it to a separate thread it works.
    Output:
    [D] Requester::action:27 - Sending request in thread "MainThread"
    [D] Provider::handleRequest:20 - Received request in thread "ProvideThread"
    [D] Requester::receiveResult:34 - Received result 2 in thread "MainThread"
    [D] Requester::action:30 - Finished waiting for result in thread "MainThread"

    1 Reply Last reply
    0
    • R Offline
      R Offline
      raspe88
      wrote on last edited by
      #2

      Do you know QFuture and QFutureInterface? Using them would make work a lot easier for you.

      You can send a QFutureInterface-object with an asynchronous signal from one thread to a worker-object in another thread while passing the future provided by the QFutureInterface-object to the thread that should receive the result.

      Don't wonder if you've never heard of QFutureInterface. It's part of QtConcurrent but not well documented. It's API is really simple. Most things you need you can find out yourself by just taking a short look into the header or using autocompletion in QtCreator. For a basic example take a look at: http://developers-club.com/posts/273743/

      I think that's what you should prefer because then you don't have to deal with own QEventLoops within QObjects within other QThreads - something that seems to be error prone to me.

      1 Reply Last reply
      1
      • R Offline
        R Offline
        rdeem
        wrote on last edited by
        #3

        I have some knowledge about QFuture, but if I have understood correctly the returned value will not be available until "later". In this specific case I cannot continue execution in the requesting thread until I know the returned value so I assume that I have to use some kind of wait anyway even if I would use QFuture/QFutureInterface.

        Part of the reason for this question was to get a deeper understanding on how threading and QEventloop works so if possible I would prefer a solution involving QThread instead of QFuture/QtConcurrent.

        jsulmJ kshegunovK 2 Replies Last reply
        0
        • R rdeem

          I have some knowledge about QFuture, but if I have understood correctly the returned value will not be available until "later". In this specific case I cannot continue execution in the requesting thread until I know the returned value so I assume that I have to use some kind of wait anyway even if I would use QFuture/QFutureInterface.

          Part of the reason for this question was to get a deeper understanding on how threading and QEventloop works so if possible I would prefer a solution involving QThread instead of QFuture/QtConcurrent.

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @rdeem Why not use http://doc.qt.io/qt-5.7/qfuture.html#waitForFinished

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          R 1 Reply Last reply
          2
          • R rdeem

            I have some knowledge about QFuture, but if I have understood correctly the returned value will not be available until "later". In this specific case I cannot continue execution in the requesting thread until I know the returned value so I assume that I have to use some kind of wait anyway even if I would use QFuture/QFutureInterface.

            Part of the reason for this question was to get a deeper understanding on how threading and QEventloop works so if possible I would prefer a solution involving QThread instead of QFuture/QtConcurrent.

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

            @raspe88 said in Wait for result from other thread:

            http://developers-club.com/posts/273743/

            SlotClosure<NoDeletePolicy> rotator
            {
               [this] { RotateFuncs (); },
               this,
               SIGNAL (rotateFuncs ()),
               nullptr
            };
            

            Ah, the orderliness of C++11 syntax .. we actually create an object here with a functor as first argument ... beautiful! To quote one Bob Hood from the mailing list:

            As much as the standards committee is trying to turn C++ into a scripting language, it still has it's roots in C, and Here Be Monsters for the uninitiated.

            @rdeem said in Wait for result from other thread:

            I have to use some kind of wait anyway even if I would use QFuture/QFutureInterface.

            @jsulm has suggested the better way. The simplest, low-level thing you can do is to just use a semaphore (untested, but should work):

            class Requester : public QObject
            {
                Q_OBJECT
            
            signals:
                void requestData();
                void needsResult();
            
            public:
                void action()
                {
                    qDebug() << "Sending request in thread" << thread()->currentThread()->objectName();
                    emit requestData();
                    emit needsResult();
            
                    qDebug() << "Finished waiting for result in thread" << thread()->currentThread()->objectName();
                }
            
            public slots:
                void receiveResult(int result)
                {
                    qDebug() << "Received result" << result << "in thread" << thread()->currentThread()->objectName();
                }
            

            and

            class Provider : public QObject
            {
                Q_OBJECT
            
            signals:
                void resultReady(int result);
            
            public slots:
                void handleRequest()
                {
                    qDebug() << "Received request in thread" << thread()->currentThread()->objectName();
                    emit sendResult(2);
                    lock.release();
                }
            
                void waitForResult()
                {
                    lock.acquire();
                }
            
            private:
                QSemaphore lock;
            };
            

            Then you use as usual:

            int main(int argc, char ** argv)
            {
                QCoreApplication app(argc, argv);
            
                Requester requester;
                Provider provider;
               
                QThread requestThread, provideThread;
                requestThread.setObjectName("RequestThread");
                provideThread.setObjectName("ProvideThread");
                QThread::currentThread()->setObjectName("MainThread");
            
                requester.moveToThread(&requestThread);
                provider.moveToThread(&provideThread);
            
                QObject::connect(&requester, &Requester::requestData, &provider, &Provider::handleRequest);
                QObject::connect(&provider, &Provider::resultReady, &requester, &Requester::receiveResult);
                QObject::connect(&requester, &Requester::needsResult, &provider, &Provider::waitForResult, Qt::DirectConnection); //< Notice the connection type
            
                // These two are only for the sake of the example, so it doesn't run forever.
                QObject::connect(&provider, &Provider::resultReady, &requestThread, &QThread::quit);
                QObject::connect(&provider, &Provider::resultReady, &provideThread, &QThread::quit);
            
                requestThread.start();
                provideThread.start();
            
                requester.action();
            
                requestThread.wait();
                provideThread.wait();
            
                return 0;
            }
            

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            4
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Hi,

              I was wondering if your current setup shouldn't be modeled using a state machine ?

              • Step 1: request data
              • Transition from Step 1 to Step 2 on dataArrived signal emitted by Provider object
              • Step 2: do processing
              • Transition back to Step 1

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              3
              • jsulmJ jsulm

                @rdeem Why not use http://doc.qt.io/qt-5.7/qfuture.html#waitForFinished

                R Offline
                R Offline
                rdeem
                wrote on last edited by rdeem
                #7

                @jsulm said in Wait for result from other thread:

                @rdeem Why not use http://doc.qt.io/qt-5.7/qfuture.html#waitForFinished

                Thanks! It looks like I should take a closer look at QFuture.

                @kshegunov said in Wait for result from other thread:

                @jsulm has suggested the better way. The simplest, low-level thing you can do is to just use a semaphore (untested, but should work):

                You may be right. I need to evaluate QFuture and your semaphore solution, but now I at least have a way forward. Thanks!

                @SGaist said in Wait for result from other thread:

                Hi,

                I was wondering if your current setup shouldn't be modeled using a state machine ?

                • Step 1: request data
                • Transition from Step 1 to Step 2 on dataArrived signal emitted by Provider object
                • Step 2: do processing
                • Transition back to Step 1

                Yes, this would require some refactoring, but it would be a very nice solution! I guess I need to rethink my design approach a little bit. :)

                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