Stop Qt Thread : calling exit() or quit() does not stop the thread execution

后端 未结 3 1111
野的像风
野的像风 2021-01-19 01:10

Created a QThread in main() i.e Main thread. Moved a worker class to the new thread. The thread executes the \'StartThread\' method of worker class.

Worker Thread:

3条回答
  •  挽巷
    挽巷 (楼主)
    2021-01-19 01:25

    isInterruptionRequested only returns true if you've called QThread::requestInterruption, not QThread::quit. This is documented.

    If you want to use QThread::quit, the thread must spin an event loop, so you shouldn't be deriving from it; instead do this:

    class Worker : public QObject {
      QBasicTimer m_timer;
      int chunksToDo = 20;
      void doChunkOfWork() {
        QThread::sleep(1);
      }
      void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() != m_timer.timerId()) return;
        if (!chunksToDo) { m_timer.stop(); return; }
        doChunkOfWork();
        if (!--chunksToDo) emit done();
      }
    public:
      explicit Worker(QObject * parent = nullptr) : QObject{parent} {
        m_timer.start(0, this);
      }
      Q_SIGNAL void done();
    };
    

    To run the worker, create it and move it to some its thread. To stop the worker, just quit() its thread before the worker is done.

    int main(int argc, char ** argv) {
      QCoreApplication app{argc, argv};
      Worker worker;
      QThread thread;
      worker.moveToThread(&thread);
      QObject::connect(&worker, &Worker::done, &thread, &QThread::quit);
      QObject::connect(&thread, &QThread::finished, &app, &QCoreApplication::quit);
      thread.start();
      return app.exec();
    }
    

    Instead of managing the thread's life manually, you might wish to use a thread pool instead.

    class Worker : public QObject, QRunnable {
      int chunksToDo = 20;
      volatile bool active = true;
      void doChunkOfWork() {
        QThread::sleep(1);
      }
      void run() {
        while (active && chunksToDo) {
          doChunkOfWork();
          --chunksToDo;
        }
        emit done();
      }
    public:
      using QObject::QObject;
      Q_SLOT void stop() { active = false; }
      Q_SIGNAL void done();
    };
    
    int main(int argc, char ** argv) {
      QCoreApplication app{argc, argv};
      QThreadPool pool;
      Worker worker;
      worker.setAutoDelete(false); // important!
      pool.start(&worker);
      // *
      QTimer::singleShot(5000, &worker, &Worker::stop);
      QObject::connect(&worker, &Worker::done, &app, &QCoreApplication::quit);
      return app.exec();
    }
    

    An alternate way to end it without running the main event loop would have been:

      // *
      QThread::sleep(5);
      worker.stop();
      pool.waitForDone();
    }
    

    This answer has a complete example of streaming multiple jobs to a thread pool.

提交回复
热议问题