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. QFutureWatcher not watching???
Forum Updated to NodeBB v4.3 + New Features

QFutureWatcher not watching???

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 3 Posters 709 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.
  • B Offline
    B Offline
    BwvB
    wrote on last edited by
    #1

    I can't get get hold of signals (resultReadyAt, finished) coming from a QFutureWatcher. The different tasks running in different thread run allright, but I get no feedback from the overseeing QFutureWatcher, despite having connected the appropriate signals.
    My demo class, MyClass, is very simple. It holds an integer _n that is initialised in the constructor, and another integer _ms that is initialised to -1:

    class MyClass
    {
    private:
       int _n;
       int _ms = -1;
    public:
       MyClass() = default;
       MyClass( int n )
          : _n( n )
       {}
    public:
       int  n() const { return _n; }
       void setms( int ival ) { _ms = ival; }
    };
    

    Then I have a worker function, that operates on an object of class MyClass. It reads the integer _n after which it sets a value for the other integer, _ms. It sleeps for _ms milliseconds, just to emulate a real computation.

    void worker( MyClass& myclass )
    {
       qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "...";
    
       MyClass newobj( myclass.n() );
       int     ms = 1000 * myclass.n();
       std::this_thread::sleep_for( std::chrono::milliseconds( ms ) );
       newobj.setms( ms );
    
       qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "done";
    }
    

    Finally, the class Scheduler below has a vector with various MyClass objects as well as a QFutureWatcher. The method called "runAll" connect two signals from the watcher to two verbose routines in the Scheduler after which the job is launched.

    class Scheduler : public QObject
    {
       Q_OBJECT
       using watchertype = QFutureWatcher<void>;
    
    public:
       std::vector<MyClass> _taskvec; // QList<MyClass*> gives the same result
       watchertype          _watcher;
    
    public:
       void runAll()
       {
          QObject::connect( &_watcher, &watchertype::resultReadyAt, this, &Scheduler::taskReady );
          QObject::connect( &_watcher, &watchertype::finished, this, &Scheduler::finished );
    
          // Launch the job.
          _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );
          qDebug() << "line:" << __LINE__ << "wait for finish ...";
          _watcher.waitForFinished();
          qDebug() << "line:" << __LINE__ << "... all done!";
       }
    public slots:
       void taskReady( int n ) { std::cerr << "taskReady: n=" << n << std::endl; }
       void finished() { std::cerr << "finished!" << std::endl; }
    };
    

    The main program:

    int main( int argc, char* argv[] )
    {
       // QCoreApplication qappl( argc, argv ); // has no effect
    
       Scheduler scheduler;
       scheduler._taskvec.push_back( MyClass( 1 ) );
       scheduler._taskvec.push_back( MyClass( 7 ) );
       scheduler._taskvec.push_back( MyClass( 3 ) );
       scheduler._taskvec.push_back( MyClass( 2 ) );
       scheduler._taskvec.push_back( MyClass( 0 ) );
       scheduler.runAll();
    }
    

    The output: no message from Scheduler::finished() or Scheduler::taskReady().

    line: 68 wait for finish ...
    line: 39 task 1 ...
    line: 39 task 7 ...
    line: 39 task 2 ...
    line: 39 task 3 ...
    line: 39 task 0 ...
    line: 46 task 0 done
    line: 46 task 1 done
    line: 46 task 2 done
    line: 46 task 3 done
    line: 46 task 7 done
    line: 70 ... all done!
    

    All tasks seems to be ok. But not any printing coming from the routines finished and taskReady, despite being connected to the watcher. What am I doing wrong?

    For completeness, in case you want to see it yourself, I will copy below the full source file (one file, main.cpp) as well as a CMakeList.txt. You might need to change the Qt6-location.
    main.cpp:

    ///////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////
    
    #include <chrono>
    #include <iostream>
    #include <string>
    #include <thread>
    #include <vector>
    
    #include <QtConcurrent/QtConcurrent>
    #include <QtCore/QCoreApplication>
    #include <QtCore/QDebug>
    #include <QtCore/QObject>
    
    /*############################################################################*/
    /*############################################################################*/
    class MyClass
    {
    private:
       int _n;
       int _ms = -1;
    
    public:
       MyClass() = default;
    
       MyClass( int n )
          : _n( n )
       {}
    
    public:
       int  n() const { return _n; }
       void setms( int ival ) { _ms = ival; }
    };
    
    /*############################################################################*/
    /*############################################################################*/
    void worker( MyClass& myclass )
    {
       qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "...";
    
       MyClass newobj( myclass.n() );
       int     ms = 1000 * myclass.n();
       std::this_thread::sleep_for( std::chrono::milliseconds( ms ) );
       newobj.setms( ms );
    
       qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "done";
    }
    
    /*############################################################################*/
    /*############################################################################*/
    class Scheduler : public QObject
    {
       Q_OBJECT
       using watchertype = QFutureWatcher<void>;
    
    public:
       std::vector<MyClass> _taskvec; // QList<MyClass*> gives the same result
       watchertype          _watcher;
    
    public:
       void runAll()
       {
          QObject::connect( &_watcher, &watchertype::resultReadyAt, this, &Scheduler::taskReady );
          QObject::connect( &_watcher, &watchertype::finished, this, &Scheduler::finished );
    
          // Launch the job.
          _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );
          qDebug() << "line:" << __LINE__ << "wait for finish ...";
          _watcher.waitForFinished();
          qDebug() << "line:" << __LINE__ << "... all done!";
       }
    
    public slots:
       void taskReady( int n ) { std::cerr << "taskReady: n=" << n << std::endl; }
       void finished() { std::cerr << "finished!" << std::endl; }
    };
    
    #include "main.moc"
    
    /*############################################################################*/
    /*############################################################################*/
    int main( int argc, char* argv[] )
    {
       // QCoreApplication qappl( argc, argv ); // has no effect
    
       Scheduler scheduler;
       scheduler._taskvec.push_back( MyClass( 1 ) );
       scheduler._taskvec.push_back( MyClass( 7 ) );
       scheduler._taskvec.push_back( MyClass( 3 ) );
       scheduler._taskvec.push_back( MyClass( 2 ) );
       scheduler._taskvec.push_back( MyClass( 0 ) );
       scheduler.runAll();
    }
    // -- eof --
    

    CMakeList.txt:

    cmake_minimum_required(VERSION 3.17)
    
    project( qfuturewatcher VERSION 1.0
             DESCRIPTION "minimul program using QFeatureWatcher"
             LANGUAGES CXX )
    
    # qt components
    find_package( Qt6 COMPONENTS Core Concurrent REQUIRED )
    
    set(CMAKE_AUTOMOC ON) # For meta object compiler
    set(CMAKE_AUTORCC ON) # Resource files
    set(CMAKE_AUTOUIC ON) # UI files
    
    FILE( GLOB sources "*.cpp" "*.qrc" )
    
    add_executable( ${PROJECT_NAME} ${sources} )
    target_link_libraries( ${PROJECT_NAME} Qt::Concurrent Qt::Core )
    
    #===end-of-file===
    
    1 Reply Last reply
    0
    • JonBJ JonB

      @BwvB said in QFutureWatcher not watching???:

      The other slot, supposedly being triggered by the resultReadyAt(int) signal, remains silent however.

      _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );

      Concurrent Map

      QtConcurrent::mapped() takes an input sequence and a map function. This map function is then called for each item in the sequence, and a new sequence containing the return values from the map function is returned.

      If you want to modify a sequence in-place, use QtConcurrent::map().
      Note that the return value and return type of the map function are not used.
      Using QtConcurrent::map() is similar to using QtConcurrent::mapped():
      Since the sequence is modified in place, QtConcurrent::map() does not return any results via QFuture. However, you can still use QFuture and QFutureWatcher to monitor the status of the map.

      So with map() you can only get finished, not resultReadyAt. Try using mapped() for the latter?

      B Offline
      B Offline
      BwvB
      wrote on last edited by
      #5

      @JonB You are right! When I tried with QtConcurrrent::mapped (a few other changes are then needed as well) the behaviour is as expected, with the resultReadyAt() signal being emitted. Thanks very much for the suggestion. I had read the manual page as well, but never interpreted the way you did!
      I will close the issue, but I wonder if this is not just a bug in Qt. After all, whether it is map or mapped, one still wants to follow progress, I would say!

      Thanks again.
      Bertwim

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

        Hi,

        Two things that jumps to my eyes: the use of waitForFinished -> you are blocking the event loop so it can't process anything and you don't have an event loop running since you don't have a QCoreApplication instance nor call exec on it so it's even surprising that it does not crash.

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

        B 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi,

          Two things that jumps to my eyes: the use of waitForFinished -> you are blocking the event loop so it can't process anything and you don't have an event loop running since you don't have a QCoreApplication instance nor call exec on it so it's even surprising that it does not crash.

          B Offline
          B Offline
          BwvB
          wrote on last edited by
          #3

          @SGaist Thanks for your response. It partly helped. I have now embedded the main code in an event loop, as you suggested. I also put, in the finished() slot, a call to quit the application.
          The call to waitForFinished() seems unneccessary (no difference with or without it) so I left it out.
          This partly worked! The output now becomes:

          line: 39 task 7 ...
          line: 39 task 3 ...
          line: 39 task 1 ...
          line: 39 task 2 ...
          line: 39 task 0 ...
          line: 46 task 0 done
          line: 46 task 1 done
          line: 46 task 2 done
          line: 46 task 3 done
          line: 46 task 7 done
          ==>finished!
          

          That is, the finished() slot is being called indeed. The other slot, supposedly being triggered by the resultReadyAt(int) signal, remains silent however.
          Full code follows now:

          #include <chrono>
          #include <iostream>
          #include <string>
          #include <thread>
          #include <vector>
          
          #include <QtConcurrent/QtConcurrent>
          #include <QtCore/QCoreApplication>
          #include <QtCore/QDebug>
          #include <QtCore/QObject>
          
          /*############################################################################*/
          /*############################################################################*/
          class MyClass
          {
          private:
             int _n;
             int _ms = -1;
          
          public:
             MyClass() = default;
          
             MyClass( int n )
                : _n( n )
             {}
          
          public:
             int  n() const { return _n; }
             void setms( int ival ) { _ms = ival; }
          };
          
          /*############################################################################*/
          /*############################################################################*/
          void worker( MyClass& myclass )
          {
             qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "...";
          
             MyClass newobj( myclass.n() );
             int     ms = 1000 * myclass.n();
             std::this_thread::sleep_for( std::chrono::milliseconds( ms ) );
             newobj.setms( ms );
          
             qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "done";
          }
          
          /*############################################################################*/
          /*############################################################################*/
          class Scheduler : public QObject
          {
             Q_OBJECT
             using watchertype = QFutureWatcher<void>;
          
          public:
             std::vector<MyClass> _taskvec; // QList<MyClass*> gives the same result
             watchertype          _watcher;
          
          public:
             void runAll()
             {
                QObject::connect( &_watcher, &watchertype::resultReadyAt, this, &Scheduler::taskReady );
                QObject::connect( &_watcher, &watchertype::finished, this, &Scheduler::finished );
          
                // Launch the job.
                _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );
             }
          
          public slots:
             void taskReady( int n ) { std::cerr << "==>taskReady: n=" << n << std::endl; }
             void finished()
             {
                std::cerr << "==>finished!" << std::endl;
                QCoreApplication::instance()->quit();
             }
          };
          
          #include "main.moc"
          
          /*############################################################################*/
          /*############################################################################*/
          int main( int argc, char* argv[] )
          {
             QCoreApplication qappl( argc, argv );
          
             Scheduler scheduler;
             scheduler._taskvec.push_back( MyClass( 1 ) );
             scheduler._taskvec.push_back( MyClass( 7 ) );
             scheduler._taskvec.push_back( MyClass( 3 ) );
             scheduler._taskvec.push_back( MyClass( 2 ) );
             scheduler._taskvec.push_back( MyClass( 0 ) );
             scheduler.runAll();
          
             qappl.exec();
          }
          // -- eof --
          
          JonBJ 1 Reply Last reply
          0
          • B BwvB

            @SGaist Thanks for your response. It partly helped. I have now embedded the main code in an event loop, as you suggested. I also put, in the finished() slot, a call to quit the application.
            The call to waitForFinished() seems unneccessary (no difference with or without it) so I left it out.
            This partly worked! The output now becomes:

            line: 39 task 7 ...
            line: 39 task 3 ...
            line: 39 task 1 ...
            line: 39 task 2 ...
            line: 39 task 0 ...
            line: 46 task 0 done
            line: 46 task 1 done
            line: 46 task 2 done
            line: 46 task 3 done
            line: 46 task 7 done
            ==>finished!
            

            That is, the finished() slot is being called indeed. The other slot, supposedly being triggered by the resultReadyAt(int) signal, remains silent however.
            Full code follows now:

            #include <chrono>
            #include <iostream>
            #include <string>
            #include <thread>
            #include <vector>
            
            #include <QtConcurrent/QtConcurrent>
            #include <QtCore/QCoreApplication>
            #include <QtCore/QDebug>
            #include <QtCore/QObject>
            
            /*############################################################################*/
            /*############################################################################*/
            class MyClass
            {
            private:
               int _n;
               int _ms = -1;
            
            public:
               MyClass() = default;
            
               MyClass( int n )
                  : _n( n )
               {}
            
            public:
               int  n() const { return _n; }
               void setms( int ival ) { _ms = ival; }
            };
            
            /*############################################################################*/
            /*############################################################################*/
            void worker( MyClass& myclass )
            {
               qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "...";
            
               MyClass newobj( myclass.n() );
               int     ms = 1000 * myclass.n();
               std::this_thread::sleep_for( std::chrono::milliseconds( ms ) );
               newobj.setms( ms );
            
               qDebug() << "line:" << __LINE__ << "task" << myclass.n() << "done";
            }
            
            /*############################################################################*/
            /*############################################################################*/
            class Scheduler : public QObject
            {
               Q_OBJECT
               using watchertype = QFutureWatcher<void>;
            
            public:
               std::vector<MyClass> _taskvec; // QList<MyClass*> gives the same result
               watchertype          _watcher;
            
            public:
               void runAll()
               {
                  QObject::connect( &_watcher, &watchertype::resultReadyAt, this, &Scheduler::taskReady );
                  QObject::connect( &_watcher, &watchertype::finished, this, &Scheduler::finished );
            
                  // Launch the job.
                  _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );
               }
            
            public slots:
               void taskReady( int n ) { std::cerr << "==>taskReady: n=" << n << std::endl; }
               void finished()
               {
                  std::cerr << "==>finished!" << std::endl;
                  QCoreApplication::instance()->quit();
               }
            };
            
            #include "main.moc"
            
            /*############################################################################*/
            /*############################################################################*/
            int main( int argc, char* argv[] )
            {
               QCoreApplication qappl( argc, argv );
            
               Scheduler scheduler;
               scheduler._taskvec.push_back( MyClass( 1 ) );
               scheduler._taskvec.push_back( MyClass( 7 ) );
               scheduler._taskvec.push_back( MyClass( 3 ) );
               scheduler._taskvec.push_back( MyClass( 2 ) );
               scheduler._taskvec.push_back( MyClass( 0 ) );
               scheduler.runAll();
            
               qappl.exec();
            }
            // -- eof --
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #4

            @BwvB said in QFutureWatcher not watching???:

            The other slot, supposedly being triggered by the resultReadyAt(int) signal, remains silent however.

            _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );

            Concurrent Map

            QtConcurrent::mapped() takes an input sequence and a map function. This map function is then called for each item in the sequence, and a new sequence containing the return values from the map function is returned.

            If you want to modify a sequence in-place, use QtConcurrent::map().
            Note that the return value and return type of the map function are not used.
            Using QtConcurrent::map() is similar to using QtConcurrent::mapped():
            Since the sequence is modified in place, QtConcurrent::map() does not return any results via QFuture. However, you can still use QFuture and QFutureWatcher to monitor the status of the map.

            So with map() you can only get finished, not resultReadyAt. Try using mapped() for the latter?

            B 1 Reply Last reply
            1
            • JonBJ JonB

              @BwvB said in QFutureWatcher not watching???:

              The other slot, supposedly being triggered by the resultReadyAt(int) signal, remains silent however.

              _watcher.setFuture( QtConcurrent::map( _taskvec, worker ) );

              Concurrent Map

              QtConcurrent::mapped() takes an input sequence and a map function. This map function is then called for each item in the sequence, and a new sequence containing the return values from the map function is returned.

              If you want to modify a sequence in-place, use QtConcurrent::map().
              Note that the return value and return type of the map function are not used.
              Using QtConcurrent::map() is similar to using QtConcurrent::mapped():
              Since the sequence is modified in place, QtConcurrent::map() does not return any results via QFuture. However, you can still use QFuture and QFutureWatcher to monitor the status of the map.

              So with map() you can only get finished, not resultReadyAt. Try using mapped() for the latter?

              B Offline
              B Offline
              BwvB
              wrote on last edited by
              #5

              @JonB You are right! When I tried with QtConcurrrent::mapped (a few other changes are then needed as well) the behaviour is as expected, with the resultReadyAt() signal being emitted. Thanks very much for the suggestion. I had read the manual page as well, but never interpreted the way you did!
              I will close the issue, but I wonder if this is not just a bug in Qt. After all, whether it is map or mapped, one still wants to follow progress, I would say!

              Thanks again.
              Bertwim

              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