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. How to stop QThread?
Forum Updated to NodeBB v4.3 + New Features

How to stop QThread?

Scheduled Pinned Locked Moved Unsolved General and Desktop
18 Posts 4 Posters 4.0k 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.
  • Q Offline
    Q Offline
    qwe3
    wrote on last edited by qwe3
    #8

    @jsulm When I do: q.exec() I wait in this line in the code, but GUI is not freezed ( I see hovers etc ). I need these calculations in these function ( in main thread ).

    jsulmJ 1 Reply Last reply
    0
    • Q qwe3

      @jsulm When I do: q.exec() I wait in this line in the code, but GUI is not freezed ( I see hovers etc ). I need these calculations in these function ( in main thread ).

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

      @qwe3 Yes, you're correct. You do not block the UI as you have a local event loop.
      Do you really have to make this synchronous?

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

      1 Reply Last reply
      0
      • Q qwe3

        Hi,
        I have application with 2 threads ( main and one for long calculations ). Codes:

        Thread with long calculations:

        Worker::Worker(QObject *parent): QObject(parent)
        {
        }
        
        void Worker::calculate()
        {
            for(int i=0; i<10000000;i++)
            {
                QCoreApplication::processEvents();
                ...
            }
        
            emit endCalc();
        }
        

        Main thread ( in one method ):

            QThread thread(this);
            Worker worker;
            worker.moveToThread(&thread);
        
            QObject::connect(&worker, &Worker::endCalc, this, &MainWindow::someSlot);
            QObject::connect(this, &MainWindow::startCal, &worker, &Worker::calculate);
        
            thread.start();
        
            QEventLoop q;
        
            connect(&worker, &Worker::endCalc, &q, &QEventLoop::quit);
        
            emit startCal();
        
            q.exec();
        
            thread.quit();
            thread.wait();
        

        And the problem is that, when I close application when there are still calculations in the second thread ( Worker ), in the main thread I wait in the line thread.wait(); and my app still running ( gui is closed, but there is still running ).

        KroMignonK Offline
        KroMignonK Offline
        KroMignon
        wrote on last edited by
        #10

        @qwe3 said in How to stop QThread?:

        And the problem is that, when I close application when there are still calculations in the second thread ( Worker ), in the main thread I wait in the line thread.wait(); and my app still running ( gui is closed, but there is still running ).

        Your design looks to me very complicate for such a "trivial" use case.
        Why you are not using QtConcurrent::run()?
        In addition with QFuturWatcher you could be informed about calculation end and got result.

        Take a look at https://doc.qt.io/qt-5/qtconcurrentrun.html.

        Or did I miss something?

        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

        1 Reply Last reply
        0
        • Q Offline
          Q Offline
          qwe3
          wrote on last edited by
          #11

          @KroMignon But can I send signals from the second thread ( long operations ) like current progress? I never used QtConcurrent.

          @jsulm Yes, I have to. I changed code and ... it doesn't work. Now it looks like this:

          Worker::Worker(QObject *parent): QObject(parent)
          {
          }
          
          void Worker::calculate()
          {
              for(int i=0; i<10000000;i++)
              {
                  QCoreApplication::processEvents();
                  if( QThread::currentThread()->isInterruptionRequested())
                  {
                              qDebug()<<"return";
                              return;
                  }    
                  ...
              }
          
              emit endCalc();
          }
          

          And in main thread ( thread is now a pointer ):

              thread->start();
          
              QEventLoop q;
          
              connect(&worker, &Worker::endCalc, &q, &QEventLoop::quit);
          
              emit startCal();
          
              q.exec();
          
              thread->requestInterruption();
              thread->quit();
              thread->wait();
          

          When I close the app using X button, I see on debuq "return", but application is still wait on thread->wait();

          jsulmJ KroMignonK 2 Replies Last reply
          0
          • Q qwe3

            @KroMignon But can I send signals from the second thread ( long operations ) like current progress? I never used QtConcurrent.

            @jsulm Yes, I have to. I changed code and ... it doesn't work. Now it looks like this:

            Worker::Worker(QObject *parent): QObject(parent)
            {
            }
            
            void Worker::calculate()
            {
                for(int i=0; i<10000000;i++)
                {
                    QCoreApplication::processEvents();
                    if( QThread::currentThread()->isInterruptionRequested())
                    {
                                qDebug()<<"return";
                                return;
                    }    
                    ...
                }
            
                emit endCalc();
            }
            

            And in main thread ( thread is now a pointer ):

                thread->start();
            
                QEventLoop q;
            
                connect(&worker, &Worker::endCalc, &q, &QEventLoop::quit);
            
                emit startCal();
            
                q.exec();
            
                thread->requestInterruption();
                thread->quit();
                thread->wait();
            

            When I close the app using X button, I see on debuq "return", but application is still wait on thread->wait();

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

            @qwe3 said in How to stop QThread?:

            connect(&worker, &Worker::endCalc, &q, &QEventLoop::quit);

            emit startCal();
            
            q.exec();
            
            thread->requestInterruption();
            

            Are you aware that requestInterruption() will be send to thread after it finished? Because q.exec() blocks until endCalc is emitted. What is the point of doing so?

            Also, you should either emit this endCalc also when termination is requested or use https://doc.qt.io/qt-5/qthread.html#finished signal to terminate the local event loop.

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

            1 Reply Last reply
            0
            • Q Offline
              Q Offline
              qwe3
              wrote on last edited by
              #13

              @jsulm When I close app and there are still operations in second thread I don't emit endCalc, but q.exec() is done.

              jsulmJ 1 Reply Last reply
              0
              • Q qwe3

                @jsulm When I close app and there are still operations in second thread I don't emit endCalc, but q.exec() is done.

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

                @qwe3 said in How to stop QThread?:

                but q.exec() is done

                How can it be done and how did you verify it is done? The only condition in your code to terminate the local event loop is endCalc signal...

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

                1 Reply Last reply
                0
                • Q Offline
                  Q Offline
                  qwe3
                  wrote on last edited by qwe3
                  #15

                  @jsulm I debuq informations like this:

                  second thread:

                  void Worker::calculate()
                  {
                      for(int i=0; i<10000000;i++)
                      {
                          QCoreApplication::processEvents();
                          if( QThread::currentThread()->isInterruptionRequested())
                          {
                                      qDebug()<<"return";
                                      return;
                          }    
                          ...
                      }
                  
                      qDebug()<<"before emit endCalc";
                      emit endCalc();
                  }
                  

                  In main thread:

                      q.exec();
                  
                     qDebug()<<"after exec";
                     thread->requestInterruption();
                     qDebug()<<"after requestInterruption";
                     thread->quit();
                     qDebug()<<"after quit";
                     thread->wait();
                  

                  When I close application I see on debuq:

                  after exec
                  after requestInterruption
                  after quit
                  return
                  

                  But it is still waiting on thread->wait();

                  So I don't emit endCalc(), but Local Event Loop is done ( of course this event loop is the second event loop in my app - the first one is in main.cpp and this one ( the second one ) is in my own class method ).

                  1 Reply Last reply
                  0
                  • Q qwe3

                    @KroMignon But can I send signals from the second thread ( long operations ) like current progress? I never used QtConcurrent.

                    @jsulm Yes, I have to. I changed code and ... it doesn't work. Now it looks like this:

                    Worker::Worker(QObject *parent): QObject(parent)
                    {
                    }
                    
                    void Worker::calculate()
                    {
                        for(int i=0; i<10000000;i++)
                        {
                            QCoreApplication::processEvents();
                            if( QThread::currentThread()->isInterruptionRequested())
                            {
                                        qDebug()<<"return";
                                        return;
                            }    
                            ...
                        }
                    
                        emit endCalc();
                    }
                    

                    And in main thread ( thread is now a pointer ):

                        thread->start();
                    
                        QEventLoop q;
                    
                        connect(&worker, &Worker::endCalc, &q, &QEventLoop::quit);
                    
                        emit startCal();
                    
                        q.exec();
                    
                        thread->requestInterruption();
                        thread->quit();
                        thread->wait();
                    

                    When I close the app using X button, I see on debuq "return", but application is still wait on thread->wait();

                    KroMignonK Offline
                    KroMignonK Offline
                    KroMignon
                    wrote on last edited by
                    #16

                    @qwe3 said in How to stop QThread?:

                    But can I send signals from the second thread ( long operations ) like current progress? I never used QtConcurrent.

                    I have no clue about what you try to do, so here is a "generic" way to do.
                    Create a QRunnable class, for example:

                    class Work : public QRunnable
                    {
                    public:
                        Work():mPromise(nullptr) {}
                        ~Work()
                        {
                            delete mPromise;
                        }
                    
                        void run()
                        {
                            int loopEnd = qrand();
                            int loopCount = 0;
                    
                            if(mPromise)
                            {
                                mPromise->reportStarted();
                                mPromise->setProgressRange(0, loopEnd);
                                mPromise->setProgressValue(0);
                            }
                            QTextStream out(stdout);
                    
                            while (loopCount < loopEnd) {
                                ++loopCount;
                                if(mPromise)
                                {
                                    if(mPromise->isCanceled())
                                        break;
                                    mPromise->setProgressValueAndText(loopCount, QString("Importing %1 frame from: %2...").arg(loopCount).arg(loopEnd));
                                }
                    
                                out << "loopCount: " << loopCount << endl;
                    
                                QThread::msleep(250);
                            }
                            if(mPromise)
                                mPromise->reportFinished();
                        }
                    
                        QFuture<void> getFuture()
                        {
                            // create future interface to be able to send progression
                            if(!mPromise) {
                                mPromise = new QFutureInterface<void>();
                                mPromise->setThreadPool(QThreadPool::globalInstance());
                                mPromise->setRunnable(this);
                            }
                            return mPromise->future();
                        }
                    
                    private:
                        QFutureInterface<void> *mPromise;
                    };
                    

                    And then use it, like this for example:

                    int main(int argc, char *argv[])
                    {
                        QCoreApplication app(argc, argv);
                    
                        QFutureWatcher<void> futureWatcherProgress;
                    
                        // ==> stop application when future is done
                        QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::finished, &app, &QCoreApplication::quit);
                        // ==> stop future on application exit
                        QObject::connect(&app, &QCoreApplication::aboutToQuit, &futureWatcherProgress, &QFutureWatcher<void>::cancel);
                    
                        // follow progression
                        QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressValueChanged, &app, [](int progressValue){
                                QTextStream out(stdout);
                                out << "Progression is" << progressValue << endl;
                            });
                            QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressRangeChanged, &app, [](int minimum, int maximum){
                                QTextStream out(stdout);
                                out << "Progression range from" << minimum << "to" << maximum << endl;
                            });
                            QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressTextChanged, &app, [](const QString &progressText) {
                                QTextStream out(stdout);
                                out << "Progression:" << progressText << endl;
                            });
                    
                            // create worker ==> QRunnable are automatically destroyed when finished (cf QRunnable::autoDelete())
                            auto runnable = new Work();
                            futureWatcherProgress.setFuture(runnable->getFuture());
                        
                           return app.exec();
                    }

                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                    1 Reply Last reply
                    0
                    • Q Offline
                      Q Offline
                      qwe3
                      wrote on last edited by qwe3
                      #17

                      @KroMignon Thank you for your code, but I don't understand how that can help me.

                      I change a little your code ( I never before used QFuture etc. so maybe I do something wrong ):

                      runnable->run(); after futureWatcherProgress.setFuture(runnable->getFuture());
                      so I have:

                                  ...
                                  auto runnable = new Work();
                      
                                  futureWatcherProgress.setFuture(runnable->getFuture());
                        
                                  runnable->run();
                      

                      And I add MainWindow like this:

                              QApplication app(argc, argv);
                              MainWindow w;
                              w.show();
                              return app.exec();
                      

                      And move code, which was in main.cpp to mainWindow like this:

                      MainWindow::MainWindow(QWidget *parent)
                          : QMainWindow(parent)
                          , ui(new Ui::MainWindow)
                      {
                          ui->setupUi(this);
                          QTimer::singleShot(1000, this, &MainWindow::fun1);
                      }
                      
                      MainWindow::~MainWindow()
                      {
                          delete ui;
                      }
                      
                      void MainWindow::fun1()
                      {
                          QFutureWatcher<void> futureWatcherProgress;
                      
                          // ==> stop application when future is done
                          QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::finished, qApp, &QCoreApplication::quit);
                          // ==> stop future on application exit
                          QObject::connect(qApp, &QCoreApplication::aboutToQuit, &futureWatcherProgress, &QFutureWatcher<void>::cancel);
                      
                          // follow progression
                          QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressValueChanged, qApp, [](int progressValue){
                                  QTextStream out(stdout);
                                  out << "Progression is" << progressValue << endl;
                              });
                              QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressRangeChanged, qApp, [](int minimum, int maximum){
                                  QTextStream out(stdout);
                                  out << "Progression range from" << minimum << "to" << maximum << endl;
                              });
                              QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressTextChanged, qApp, [](const QString &progressText) {
                                  QTextStream out(stdout);
                                  out << "Progression:" << progressText << endl;
                              });
                      
                              // create worker ==> QRunnable are automatically destroyed when finished (cf QRunnable::autoDelete())
                              auto runnable = new Work();
                      
                              futureWatcherProgress.setFuture(runnable->getFuture());
                      
                              runnable->run();
                      }
                      

                      And this code freeze GUI ( mainWindow ). I add second thread to unfreeze GUI.

                      KroMignonK 1 Reply Last reply
                      0
                      • Q qwe3

                        @KroMignon Thank you for your code, but I don't understand how that can help me.

                        I change a little your code ( I never before used QFuture etc. so maybe I do something wrong ):

                        runnable->run(); after futureWatcherProgress.setFuture(runnable->getFuture());
                        so I have:

                                    ...
                                    auto runnable = new Work();
                        
                                    futureWatcherProgress.setFuture(runnable->getFuture());
                          
                                    runnable->run();
                        

                        And I add MainWindow like this:

                                QApplication app(argc, argv);
                                MainWindow w;
                                w.show();
                                return app.exec();
                        

                        And move code, which was in main.cpp to mainWindow like this:

                        MainWindow::MainWindow(QWidget *parent)
                            : QMainWindow(parent)
                            , ui(new Ui::MainWindow)
                        {
                            ui->setupUi(this);
                            QTimer::singleShot(1000, this, &MainWindow::fun1);
                        }
                        
                        MainWindow::~MainWindow()
                        {
                            delete ui;
                        }
                        
                        void MainWindow::fun1()
                        {
                            QFutureWatcher<void> futureWatcherProgress;
                        
                            // ==> stop application when future is done
                            QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::finished, qApp, &QCoreApplication::quit);
                            // ==> stop future on application exit
                            QObject::connect(qApp, &QCoreApplication::aboutToQuit, &futureWatcherProgress, &QFutureWatcher<void>::cancel);
                        
                            // follow progression
                            QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressValueChanged, qApp, [](int progressValue){
                                    QTextStream out(stdout);
                                    out << "Progression is" << progressValue << endl;
                                });
                                QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressRangeChanged, qApp, [](int minimum, int maximum){
                                    QTextStream out(stdout);
                                    out << "Progression range from" << minimum << "to" << maximum << endl;
                                });
                                QObject::connect(&futureWatcherProgress, &QFutureWatcher<void>::progressTextChanged, qApp, [](const QString &progressText) {
                                    QTextStream out(stdout);
                                    out << "Progression:" << progressText << endl;
                                });
                        
                                // create worker ==> QRunnable are automatically destroyed when finished (cf QRunnable::autoDelete())
                                auto runnable = new Work();
                        
                                futureWatcherProgress.setFuture(runnable->getFuture());
                        
                                runnable->run();
                        }
                        

                        And this code freeze GUI ( mainWindow ). I add second thread to unfreeze GUI.

                        KroMignonK Offline
                        KroMignonK Offline
                        KroMignon
                        wrote on last edited by KroMignon
                        #18

                        @qwe3 said in How to stop QThread?:

                        I change a little your code ( I never before used QFuture etc. so maybe I do something wrong ):
                        runnable->run(); after futureWatcherProgress.setFuture(runnable->getFuture());

                        Okay, my code was o a little bit too rough, so I will be more explicit:

                        • a create a class based on QRunnable to be able to use it with QThreadPool.
                        • in the method getFuture(), the class instance is transformed to future a will run in next thread available the thread pool. So the run() method will be called a soon as possible
                        • after that I record the QFuture instance returned into the QFutureWatcher instance to be aware about state changes.

                        Your fun1() don't made sense; the QFutureWatcher is a local variable which will be delete at function end!
                        Change it like this:

                        void MainWindow::fun1()
                        {
                            // do NOT use a local variable!!!
                            auto futureWatcherProgress = new QFutureWatcher<void>();
                        
                            // ==> delete QFuteWatcher instance instance when process done
                            connect(futureWatcherProgress, &QFutureWatcher<void>::finished, futureWatcherProgress, [futureWatcherProgress]() {
                                futureWatcherProgress->deleteLater();
                                qDebug() << "Processing done.";
                            });
                            // ==> stop future on application exit
                            connect(qApp, &QCoreApplication::aboutToQuit, futureWatcherProgress, &QFutureWatcher<void>::cancel);
                        
                            // follow progression
                            connect(futureWatcherProgress, &QFutureWatcher<void>::progressValueChanged, this, [](int progressValue){
                                qDebug() << "Progression is" << progressValue;
                            });
                            connect(futureWatcherProgress, &QFutureWatcher<void>::progressRangeChanged, this, [](int minimum, int maximum){
                                qDebug()<< "Progression range from" << minimum << "to" << maximum;
                            });
                            connect(&futureWatcherProgress, &QFutureWatcher<void>::progressTextChanged, qApp, [](const QString &progressText) {
                                qDebug() << "Progression:" << progressText;
                            });
                        
                            // create worker ==> QRunnable are automatically destroyed when finished (cf QRunnable::autoDelete())
                            auto runnable = new Work();
                        
                            // register future and start processing
                            futureWatcherProgress->setFuture(runnable->getFuture());
                        }
                        

                        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                        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