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

后端 未结 3 1109
野的像风
野的像风 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.

    0 讨论(0)
  • 2021-01-19 01:25

    You seem to have many misconceptions.

    From the Qt docs, both QThread::quit() and QThread::exit():

    Tell the thread's event loop to exit

    That means that if the thread's event loop is not running (either QThread::exec() have not been called or the event loop busy executing some heavy blocking function(like your StartThread)) , the thread will not quit until the control is back into the event loop. I think that explains why quit() and exit() did not work for you as expected.

    Also you seem to be using QThread::requestInterruption() in a wrong way, back to the Qt docs:

    Request the interruption of the thread. 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. This function does not stop any event loop running on the thread and does not terminate it in any way.

    so this does not really do any thing with your thread, it just causes subsequent calls to QThread::isInterruptionRequested() to return true, so that when you detect that (within the thread) you should perform clean-up and quit as soon as possible (again in order for quit() to work here, the event loop should be running, so you should return from your StartThread function here, to get the thread back into its event loop again).

    Now to answer your question:

    Is it possible to stop/dispose the thread as in when required by the main thread?

    To do that, you should either avoid such long running functions and make sure you return to the event loop as soon as possible, so that quit()/exit() can work. Or perform clean-up and return from the current function as soon as you detect that isInterruptionRequested() is returning true, so that calls to quit()/exit() can work after that.

    As pointed out by @kuba you may choose to use a thread pool instead of managing your thread's life manually.

    P.S. you don't have to store a pointer to your QThread inside the Worker in order to use isInterruptionRequested(). you can use QThread::currentThread()->isInterruptionRequested() instead of m_pCurrentThread->isInterruptionRequested() (the same thing applies to your exit call m_pCurrentThread->isInterruptionRequested())

    0 讨论(0)
  • 2021-01-19 01:44

    You declared and initialized count inside the while loop. Move it outside and it will stop reinitializing to zero every iteration, and thus quit on time. I'm unclear why you've declared it static, as well.

    Note
    If you intend to use queued signals and handle events, make sure you periodically call processEvents on the thread's event dispatcher inside your while loop:

    if (thread()->eventDispatcher()->hasPendingEvents()
        thread()->eventDispatcher()->processEvents();
    
    0 讨论(0)
提交回复
热议问题