Two uses of QThread

Posted by podarum on Sun, 02 Jan 2022 20:28:36 +0100

1, Multithreading purpose

The QThread class provides a platform independent method for managing threads.
The main purpose of establishing threads in Qt is to use threads to deal with time-consuming background operations, such as massive operations, copying large files, network transmission, etc.

2, Qt multithreading usage

  • When using Qt framework to develop applications, QThread class can be used to create and manage multithreads easily and quickly.
  • The communication between multithreads can also be realized by Qt's unique "signal slot" mechanism.
    QThread can be used in the following two ways:
    1. Inherit QThread class
    2. QObject::moveToThread()

2.1 inherit QThread method

The first method is very simple and easy to understand. Write a class to inherit the QThread class, rewrite the run() function, generate an instance of ChildThread in the main thread, and call the start() function of the object

First, define the FileCopyThread class, inherit QThread, and add two signals
//FileCopyThread.h

#ifndef CHILDTHREAD_H
#define CHILDTHREAD_H

#include <QThread>

class FileCopyThread : public QThread
{
    Q_OBJECT
public:
    explicit FileCopyThread();
    ~FileCopyThread();

protected:
    void run() override;   //Rewriting the virtual function of QThread class is also the entry function of thread subclass

signals:
    void done();                        //Completion signal
    void reportProgress(int precent);   //Report completion progress
};

#endif // CHILDTHREAD_H

FileCopyThread.cpp

#include "childthread.h"
#include <QMessageBox>

FileCopyThread::FileCopyThread()
{

}

FileCopyThread::~FileCopyThread()
{

}

void FileCopyThread::run()
{
    for (int i = 0; i <= 10; i++)//Simulation time-consuming operation
    {
        QThread::msleep(500);
        emit reportProgress(i*10);
    }
    emit done();
}

In the main thread, the following is called:

 FileCopyThread* t = new FileCopyThread;
    connect(t, &FileCopyThread::reportProgress, ui->progressBar, &QProgressBar::setValue);
    connect(t, SIGNAL(done()), this, SLOT(onCopyFinished()));
    t->start();

2.2 QObject::moveToThread

To tell you the truth, I don't quite understand this method o(╥﹏╥) O

  1. Define a common QObject derived class FileWorker, and then move its object to QThread.
  2. When defining a forwarding class, which is also a subclass of QObject, it is called controller or dummy. Associates the signal slot of the forwarding class with the signal slot of the FileWorker class, so that the slot function of the forwarding class is called in the main thread, or the received signal is OK.
    It probably means that the slot function of FileWorker class can run properly in the sub thread through the forwarding class. At the same time, there is no need to use QMutex for synchronization. The event loop of Qt will automatically handle this.
    //FileWorker.h
#ifndef FILEWORKER_H
#define FILEWORKER_H

#include <QObject>
#include <QThread>

class FileWorker : public QObject
{
    Q_OBJECT
public:
    explicit FileWorker(QObject *parent = nullptr);

signals:
    void done();                        //Completion signal
    void reportProgress(int precent);   //Report completion progress

private slots:
    void doWork();//What the thread needs to do
};

#endif // FILEWORKER_H

//FileWorker.cpp

#include "fileworker.h"
#include <QDebug>

FileWorker::FileWorker(QObject *parent) : QObject(parent)
{

}

void FileWorker::doWork()
{
    qDebug()<<"from thread doWork slot:" <<QThread::currentThreadId();
    for (int i = 0; i <= 10; i++)//Simulation time-consuming operation
    {
        QThread::msleep(500);
        emit reportProgress(i*10);
    }
    emit done();
}

//Controller.h

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QObject>

class Controller : public QObject
{
    Q_OBJECT
public:
    explicit Controller(QObject *parent = nullptr);

signals:
    void sig_copy();

    void done();                        //Completion signal
    void reportProgress(int precent);   //Report completion progress

public slots:
    void startCopy();
};

#endif // CONTROLLER_H

//Controller.cpp

#include "controller.h"

Controller::Controller(QObject *parent) : QObject(parent)
{

}

void Controller::startCopy()
{
    emit sig_copy();
}

In the main thread, first associate the signal slot of the forwarding class and the worker class

    worker2.moveToThread(&t2);//FileWorker object moveToThread
    connect(&controller2, SIGNAL(sig_copy()), &worker2, SLOT(doWork()));//controller2 is the forwarding class here, and its signal is associated with the fileWorker slot
    connect(&worker2, SIGNAL(reportProgress(int)), ui->progressBar, SLOT(setValue(int)));
    connect(&worker2, SIGNAL(done()), this, SLOT(onCopyFinished()));

Finally, start the thread, and the running effect is consistent with the method.

//Method 2
void Dialog::on_pushButton_2_clicked()
{
    qDebug()<<"UI thread:"<<QThread::currentThreadId();
    t2.start();
    controller2.sig_copy();
}

3, QThread summary

  • Recommended:
    Add a signal in the QThread subclass. This is absolutely safe and correct (the thread dependency of the sender does not matter)

  • What should not be done is:
    Call the moveToThread(this) function
    Specify connection type: This usually means that you are doing something wrong, such as mixing the QThread control interface with business logic (which should be placed in a separate object of the thread)
    Add slot functions in the QThread subclass: this means that they will be called in the wrong thread, that is, the thread where the QThread object is located, rather than the thread managed by the QThread object. This requires you to specify the connection type or call the moveToThread(this) function
    Use the QThread::terminate() function

  • What you can't do is:
    Exit the program while the thread is still running. Use the QThread::wait() function to wait for the thread to end
    Destroy the QThread object while the thread it manages is still running. If you need some kind of "self destruction" operation, you can connect the finished() signal with the deleteLater() slot

    Well, it's a long way to go. I'll look up and down.

reference resources: https://blog.csdn.net/zb872676223/article/details/22718087

Topics: Qt