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
    #5

    @J-Hilk I don't understand. I don't want to freeze GUI, so I decided to create the second thread. I need to change asynchronous code to synchronous, so I find solution here:

    https://doc.qt.io/archives/qq/qq27-responsive-guis.html ( Waiting in a Local Event Loop )

    jsulmJ 1 Reply Last reply
    0
    • Q qwe3

      @jsulm Thank you. This looks very good. But I have a question:

      In docs I can read:
      That request is advisory and it is up to code running on the thread to decide if and how it should act upon such request.

      So what if thread don't accept request?

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

      @qwe3 said in How to stop QThread?:

      So what if thread don't accept request?

      Then it does not terminate.
      But sinse it's your thread you can do it the right way, right?
      If you don't want to do it right you can still kill your thread using https://doc.qt.io/qt-5/qthread.html#terminate

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

      1 Reply Last reply
      0
      • Q qwe3

        @J-Hilk I don't understand. I don't want to freeze GUI, so I decided to create the second thread. I need to change asynchronous code to synchronous, so I find solution here:

        https://doc.qt.io/archives/qq/qq27-responsive-guis.html ( Waiting in a Local Event Loop )

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

        @qwe3 said in How to stop QThread?:

        . I don't want to freeze GUI

        But you do: q.exec();
        So, you're waiting in your main thread for the other thread to terminate...

        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
          #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