QThread of Qt multithreading

Posted by deolsabh on Tue, 08 Feb 2022 04:47:49 +0100

In the project, a QThread object manages a thread. Generally speaking, the execution of a thread starts with the run () function. In Qt, there are two ways. The first is to inherit QThread and rewrite run() function. The second is to inherit QObject function and add time-consuming operations, and then call QObject::moveToThread() function. It is recommended to use moveToThread() in Qt.

When a thread starts or ends, QThread will be notified by the started() and finished() signals, or you can use isRunning() and isFinished() to query the status of the thread. You can also call exit() or quit() to stop the thread. In extreme cases, you might use terminate() to force the termination of an executing thread.

QObject::moveToThread() usage example (in the help document):

class Worker : public QObject
  {
      Q_OBJECT

  public slots:
      void doWork(const QString &parameter) {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }

  signals:
      void resultReady(const QString &result);
  };

  class Controller : public QObject
  {
      Q_OBJECT
      QThread workerThread;
  public:
      Controller() {
          Worker *worker = new Worker;
          worker->moveToThread(&workerThread);
          connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
          connect(this, &Controller::operate, worker, &Worker::doWork);
          connect(worker, &Worker::resultReady, this, &Controller::handleResults);
          workerThread.start();
      }
      ~Controller() {
          workerThread.quit();
          workerThread.wait();
      }
  public slots:
      void handleResults(const QString &);
  signals:
      void operate(const QString &);
  };

It should be noted that the Worker must inherit from QObject, otherwise the call is in the same thread. You can use QThread::currentThreadId() to determine whether it is in which thread. In this call mode, the code in the Worker thread slot will be executed in a separate thread. At the same time, you can freely connect the slot or signal in the Worker thread to any signal of any object. Because of the mechanism of queue connection, the way to connect signals and slots across different threads is safe.

Another way to use threads is to inherit QThread and override the run() function:

class WorkerThread : public QThread
  {
      Q_OBJECT
      void run() override {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }
  signals:
      void resultReady(const QString &s);
  };

  void MyObject::startWorkInAThread()
  {
      WorkerThread *workerThread = new WorkerThread(this);
      connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
      workerThread->start();
  }

In this example, the thread will exit after the run() function returns. The thread will not run any event loops unless exec() is called. It should be noted that the qthread instantiation is located in its old thread, not in the new thread calling run(). This means that all methods of slots and signals in the queue in qthread will be executed in the old thread. If you want to call the signal and slot in the new thread, the new signal and slot old can not be directly implemented in the subclass QThread. That is, when subclassing qthread, you need to remember that the constructor is executed in the old thread and run() is executed in the new thread. If a variable is accessed from these two functions, the variable is accessed from two different threads. You need to check whether it is thread safe (locked).

Topics: C++ Qt Multithreading thread