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. Qt and coroutines

Qt and coroutines

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 5 Posters 1.6k 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.
  • F Offline
    F Offline
    Fausto01
    wrote on last edited by
    #1

    I have this class:

    my_class.hpp

    #ifndef MYCLASS_HPP
    #define MYCLASS_HPP
    
    #include <QObject>
    
    class MyClass : public QObject
    {
        Q_OBJECT
      public:
        MyClass(QObject* parent = nullptr);
    
        void doWork();
    
      signals:
        void workFinished();
    };
    
    #endif // MYCLASS_HPP
    

    And I need to achieve something like that:

    void function()
    {
      MyClass myClass;
    
      qDebug() << "Doing the work...";
      myClass.doWork();
      // waiting until the workFinished() signal is emitted
      doSomethig();
      qDebug() << "Work done";
    }
    

    Can I do that with coroutines? I don't want to fill the code with lambdas inside other lambdas.
    Thank you

    jsulmJ 1 Reply Last reply
    0
    • F Fausto01

      I have this class:

      my_class.hpp

      #ifndef MYCLASS_HPP
      #define MYCLASS_HPP
      
      #include <QObject>
      
      class MyClass : public QObject
      {
          Q_OBJECT
        public:
          MyClass(QObject* parent = nullptr);
      
          void doWork();
      
        signals:
          void workFinished();
      };
      
      #endif // MYCLASS_HPP
      

      And I need to achieve something like that:

      void function()
      {
        MyClass myClass;
      
        qDebug() << "Doing the work...";
        myClass.doWork();
        // waiting until the workFinished() signal is emitted
        doSomethig();
        qDebug() << "Work done";
      }
      

      Can I do that with coroutines? I don't want to fill the code with lambdas inside other lambdas.
      Thank you

      jsulmJ Online
      jsulmJ Online
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @Fausto01 I don't understand what the problem is.
      myClass.doWork() will block until it's done, so no need to "wait". Or is it going to be executed in another thread?

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

      F 1 Reply Last reply
      0
      • jsulmJ jsulm

        @Fausto01 I don't understand what the problem is.
        myClass.doWork() will block until it's done, so no need to "wait". Or is it going to be executed in another thread?

        F Offline
        F Offline
        Fausto01
        wrote on last edited by
        #3

        @jsulm The doWork() function runs async code, it's non blocking

        jsulmJ 1 Reply Last reply
        0
        • F Fausto01

          @jsulm The doWork() function runs async code, it's non blocking

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

          @Fausto01 Then use signals and slots, no need to wait inside function().
          Connect a slot to workFinished() signal and call doSomething() there (or make doSomething() a slot and connect it directly to workFinished()).

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

          F 1 Reply Last reply
          1
          • jsulmJ jsulm

            @Fausto01 Then use signals and slots, no need to wait inside function().
            Connect a slot to workFinished() signal and call doSomething() there (or make doSomething() a slot and connect it directly to workFinished()).

            F Offline
            F Offline
            Fausto01
            wrote on last edited by
            #5

            @jsulm I know I could use signal and slots, but I wanted to use coroutines so that my code would be more linear

            Chris KawaC 1 Reply Last reply
            0
            • F Fausto01

              @jsulm I know I could use signal and slots, but I wanted to use coroutines so that my code would be more linear

              Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @Fausto01 Sounds like you want to use coroutines because you want to use coroutines. Is it really worth it?

              Anyway, it's not very Qt style, but if you really want to wait in the function until a signal comes just use local event loop. No lambdas or coroutines required.

              MyClass myClass;
              myClass.doWork();
              
              QEventLoop loop;
              connect(&myClass, &MyClass::workFinished, &loop, &QEventLoop::quit);
              loop.exec();
              
              doSomethig();
              

              You can wrap it in some function, so it's easier to reuse, e.g.

              MyClass myClass;
              myClass.doWork();
              
              waitFor(&myClass, &MyClass::workFinished);
              
              doSomethig();
              

              Answering your question directly - coroutines on their own do not specify if they run on the same or another thread. that's up to the implementation of the task class. You'd have to have support structures that would run the coroutine in another thread and wake the caller in time to pump the message queue and process the signal. That's doable, but nothing like that exists out of the box in Qt, so you'd have to implement that yourself. Sounds to me like a whole can of worms for no gain.

              F 1 Reply Last reply
              0
              • Chris KawaC Chris Kawa

                @Fausto01 Sounds like you want to use coroutines because you want to use coroutines. Is it really worth it?

                Anyway, it's not very Qt style, but if you really want to wait in the function until a signal comes just use local event loop. No lambdas or coroutines required.

                MyClass myClass;
                myClass.doWork();
                
                QEventLoop loop;
                connect(&myClass, &MyClass::workFinished, &loop, &QEventLoop::quit);
                loop.exec();
                
                doSomethig();
                

                You can wrap it in some function, so it's easier to reuse, e.g.

                MyClass myClass;
                myClass.doWork();
                
                waitFor(&myClass, &MyClass::workFinished);
                
                doSomethig();
                

                Answering your question directly - coroutines on their own do not specify if they run on the same or another thread. that's up to the implementation of the task class. You'd have to have support structures that would run the coroutine in another thread and wake the caller in time to pump the message queue and process the signal. That's doable, but nothing like that exists out of the box in Qt, so you'd have to implement that yourself. Sounds to me like a whole can of worms for no gain.

                F Offline
                F Offline
                Fausto01
                wrote on last edited by
                #7

                @Chris-Kawa yeah I've tried the QEventLoop way, but sometimes it reprocesses the same event multiple times, I think that's because I used the event loop inside a slot from QML. Is it possible?

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

                  Hi,

                  Can you explain what you want to achieve ?
                  From the outside, it seems you want to do some blocking parallelism which usually defeats the purpose of parallelism.

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

                  F 2 Replies Last reply
                  0
                  • SGaistS SGaist

                    Hi,

                    Can you explain what you want to achieve ?
                    From the outside, it seems you want to do some blocking parallelism which usually defeats the purpose of parallelism.

                    F Offline
                    F Offline
                    Fausto01
                    wrote on last edited by
                    #9

                    @SGaist my bad if I did not explain it clearly, my goal is to write the code as if it was synchronous, but it is asynchronous instead.
                    I took inspiration from QCoro library but I cannot use it.
                    I want the code to be linear as the QEvenLoop example, but I would like to not use it.

                    1 Reply Last reply
                    0
                    • SGaistS SGaist

                      Hi,

                      Can you explain what you want to achieve ?
                      From the outside, it seems you want to do some blocking parallelism which usually defeats the purpose of parallelism.

                      F Offline
                      F Offline
                      Fausto01
                      wrote on last edited by
                      #10

                      @SGaist something like that, where the get() function runs asynchronously

                      QNetworkAccessManager networkAccessManager;
                      // co_await the reply - the coroutine is suspended until the QNetworkReply is finished.
                      // While the coroutine is suspended, *the Qt event loop runs as usual*.
                      const QNetworkReply *reply = co_await networkAccessManager.get(url);
                      // Once the reply is finished, your code resumes here as if nothing amazing has just happened ;-)
                      const auto data = reply->readAll();
                      
                      Chris KawaC S 2 Replies Last reply
                      0
                      • F Fausto01

                        @SGaist something like that, where the get() function runs asynchronously

                        QNetworkAccessManager networkAccessManager;
                        // co_await the reply - the coroutine is suspended until the QNetworkReply is finished.
                        // While the coroutine is suspended, *the Qt event loop runs as usual*.
                        const QNetworkReply *reply = co_await networkAccessManager.get(url);
                        // Once the reply is finished, your code resumes here as if nothing amazing has just happened ;-)
                        const auto data = reply->readAll();
                        
                        Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by Chris Kawa
                        #11

                        @Fausto01 The problem is that you can't just suspend the execution if you're in the main thread. It needs to pump the event loop or your app will freeze. If you're not in the main thread you can suspend, but you still need an active event loop to process the finish signal and if you're blocking you might as well just block explicitly and not use coroutines.

                        I think you need to explain your use case a bit more. Where do you start the "task" - main thread or a worker. What do you want to happen with that thread - do you want it to block or keep processing events.

                        In general Qt model is event based - it needs an active message pump that processes incoming signals or system events. Coroutines are not really suited for that I think. Sure you can force any code into using them, but it kinda works against the design of the library. "I want the code to be linear" is not a good idea when the library is not designed to be used like that. You're not gonna get better code forcing the library into a pattern it wasn't designed for.

                        I've tried the QEventLoop way, but sometimes it reprocesses the same event multiple times,

                        That... doesn't sound plausible. There's really no magic to it. It's just a simple message queue. More likely you had a bug in your code, but I can't say for sure without more details.

                        1 Reply Last reply
                        3
                        • F Fausto01

                          @SGaist something like that, where the get() function runs asynchronously

                          QNetworkAccessManager networkAccessManager;
                          // co_await the reply - the coroutine is suspended until the QNetworkReply is finished.
                          // While the coroutine is suspended, *the Qt event loop runs as usual*.
                          const QNetworkReply *reply = co_await networkAccessManager.get(url);
                          // Once the reply is finished, your code resumes here as if nothing amazing has just happened ;-)
                          const auto data = reply->readAll();
                          
                          S Offline
                          S Offline
                          SimonSchroeder
                          wrote on last edited by
                          #12

                          @Fausto01 said in Qt and coroutines:

                          something like that, where the get() function runs asynchronously

                          I guess you need to further define what you mean with "asynchronously". Your example shows network communication. One of the best examples for this sort of asynchronicity is the asio lib. Another good example is signals/slots in Qt (yes, this is called asynchronous!). Both of these don't allow for a linear flow of logic in your code.

                          C++'s coroutines are still in its infancy. I do understand that it would be nice to use co_await wherever you are in your code. It is impossible to use Qt's classes, like QNetworkAccessManager, directly with coroutines. You would have to write your own class and wrap this. It does not seem to be possible to generalize coroutines for anything else. What would have to happen for the QNetworkAccessManager is something like this:

                          1. Call QNetworkAccessManager::get(url).
                          2. Create a local event loop.
                          3. Connect QNetworkReply::finished() to quit the local event loop.
                          4. Run the local event loop.

                          Certainly the local event loop part can be generalized, but connecting the right signal to finish the event loop can not.

                          Maybe, this way of thinking (in the context of Qt) is also totally backwards. Your own function (creating a QNetworkAccessManager, getting a QNetworkReply, reading the data) should be a coroutine itself. After calling QNetworkAccessManager::get() you would co_yield to return to the main event loop. But before that you need to connect QNetworkReply::finished() to a slot which will then call your coroutine again in order to continue after the co_yield. This would truly allow for linear code on your side. This approach should work with a generalized coroutine which handles interfacing the coroutine with the Qt event loop. The only thing left on the programmers side would be to connect a single signal to your own generalized coroutine's slot which would resume the coroutine.

                          1 Reply Last reply
                          0
                          • F Offline
                            F Offline
                            Fausto01
                            wrote on last edited by
                            #13

                            Thank you for all your support guys! Everything is much more clear now!

                            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