Introduction to the

When we write UI files, there are many cases, it is necessary to interface to deal with some time-consuming operations in the business, at this time if you do not deal with the interface related logic, the main interface will be stuck, at this time we need to multithreading

Logic 1

First, a very simple chestnut in business

Let’s say we have a time-consuming operation in our code

    // The first time-consuming operation
    auto fWhile1 = [] ()
    {
        for (int i = 0; i < 1000000; i++)
        {
            qDebug()<<i<<endl; }};Copy the code

Bind this code to a button event

    connect(ui->pushButton1, &QPushButton::clicked, fWhile1);
Copy the code

And then click. It is normal to find that the interface is stuck. We can not continue to operate the interface until the time consuming of this code is completed. This code is too unfriendly and not halal, so we need to change it.


Logic 2

How do YOU change it? You can look at this function, right

QCoreApplication::processEvents
Copy the code

Let’s take a look at the official website

Processes all pending events for the calling thread according to the specified flags until there are no more events to process.

You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file). In the event that you are running a local loop which calls this function continuously, without an event loop, the DeferredDelete events will not be processed. This can affect the behaviour of widgets, e.g. QToolTip, that rely on DeferredDelete events to function properly. An alternative would be to call sendPostedEvents() from within that local loop. Calling this function processes events only for the calling thread. Note: This function is thread-safe.

  • You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).
  • You can call this feature occasionally when your program is busy with long-running operations, such as copying files.

We’ll leave it at that for now. And now we can make the code look like this.

    auto fWhile2 = [] ()
    {
        for (int i = 0; i < 1000000; i++)
        {
            qDebug()<<i<<endl;
            QApplication::processEvents();
        }
    };
    connect(ui->pushButton2, &QPushButton::clicked, fWhile2);
Copy the code

This code actually has some minor problems on poorly configured machines, like my little broken book. There will still be a bit of a jam. I think users are generally okay with that.


Logic 3

In fact, there is a problem with this logic, which is what if my business code is not a loop, so we can use a new class interface

QtConcurrent::run
Copy the code

This class. This class allows a function to be executed in a new thread. Coupled with the

QFuture<T>
Copy the code

This class, which controls this new thread function to start, to control, to finish. Specific can check the official document, I here on a simple chestnut

// Time-consuming operation
static bool function_needmoretime(a)
{
    for (int i = 0; i < 1000000; i++)
    {
        qDebug()<<i<<endl;
    }
    return true;
}

    // three
    auto fWhile3 = [] () -> void
    {
        QFuture<bool> future = QtConcurrent::run(function_needmoretime);
        while(! future.isFinished())
        {
            QApplication::processEvents(QEventLoop::AllEvents, 100); }};connect(ui->pushButton3, &QPushButton::clicked, fWhile3);


Copy the code

The QFuture + QtConcurrent framework is a powerful way to abstract away thread synchronous asynchronous state from programmers’ concerns. This is just a chestnut in its simplest form. I’m using my stupid little notebook to run this. The interface is still silky smooth.


Logic 4- Threads

I’m not going to get into thread-based crap. I’ll just go to the wiki.

A thread (English: thread) is the smallest unit in which an operating system can schedule operations. It is contained within the process and is the actual operating unit within the process. A thread is a single sequential flow of control in a process, and multiple threads can be concurrent in a process, each performing a different task in parallel. In Unix System V and SunOS, they are also referred to as Lightweight processes, but more commonly referred to as kernel threads, while user threads are referred to as threads.

Threads are the basic unit of independent scheduling and dispatch. Threads Kernel threads that can be scheduled for the operating system kernel, such as Win32 threads; User threads scheduled by user processes, such as POSIX threads on Linux. Or it can be mixed by the kernel and user processes, such as Windows 7 threads. Multiple threads in the same process share all system resources in that process, such as virtual address space, file descriptors, signal processing, and so on. But multiple threads in the same process have their own call stack, their own register context, and their own thread-local storage. A process can have many threads, each performing different tasks in parallel. The benefits of using multithreaded programming on a multi-core or multi-CPU, or hyper-threading enabled CPU are obvious, namely increased program throughput. In a single CPU single-core computer, the use of multithreading technology, can also be responsible for THE PROCESS of I/O processing, human-computer interaction and often blocked part and the part of intensive computing to separate the execution, write a special workhorse thread to perform intensive computing, thus improving the efficiency of the program.

There are two ways to create threads. The first is to inherit QThread and override run, but this is no longer recommended. Let’s not write this if it’s not officially recommended, but we’re talking about the second way.

Inherit QObject and move to a new thread.

Rewrite the QObject

/ / header files
class workThread : public QObject
{
    Q_OBJECT
public:
    workThread(QObject* parent = nullptr);
    ~workThread(a);public slots:
    void start1(a);
    void doWork(a);
signals:
    void workFinished(a);
    void workStart(a);
};

//cpp
workThread::workThread(QObject* parent) : QObject (parent)
{
}
workThread::~workThread() {}void workThread::start1(a)
{
    emit workStart(a);
    doWork(a); }void workThread::doWork(a)
{
    for (int i = 0; i < 1000000; i++)
    {
        qDebug()<<i<<endl;
    }
    emit workFinished(a);
}
Copy the code

Method of use

    QThread* m_workerThread = new QThread(a); workThread* worker =new workThread(a); worker->moveToThread(m_workerThread);

    connect(m_workerThread, &QThread::started, worker, &workThread::start1);
    connect(worker, &workThread::workFinished, m_workerThread, &QThread::quit);
    connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater);

    // You can also exit to release resources
// connect(qApp, &QApplication::aboutToQuit, worker, &QObject::deleteLater);
// connect(worker, &QObject::destroyed, m_workerThread, &QThread::quit);
// connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater);
Copy the code

The bottom line is that the interface doesn’t bother at all, because we put deferred operations into a new thread. If data needs to be transmitted, it can be transmitted through a signal slot.

  • The reason why rewriting qThreads is not officially recommended is because of the inability to use signal slots
  • If you want to inherit from QThread, you can do that, and the class that inherits from QThread also needs to moveToThread, which is not halal, so you don’t want to use it.

Logic 5 thread + timer

Essentially, it’s an advanced version of logic 4, with a timer that outputs the current time every two seconds

class TimerThread : public QObject
{
    Q_OBJECT
public:
    TimerThread(QObject* parent = nullptr);
    ~TimerThread(a);public:
    void run(a);
    void doWork(a);
signals:
    void workStart(a);
    void workFinished(a);
};

static int timerCount = 0;
TimerThread::TimerThread(QObject* parent): QObject (parent)
{
}
TimerThread::~TimerThread() {}void TimerThread::run(a)
{
    emit workStart(a);
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &TimerThread::doWork);
    timer->start(2000);
}
void TimerThread::doWork(a)
{
    timerCount ++;
    if (timerCount > 100)
        emit workFinished(a);
    qDebug()<<QTime::currentTime()<<endl;
}
Copy the code

The business code is here

    auto fTimerThreadStart = [=] () -> void
    {
        fiveThread->start(a); };connect(ui->threadButton2, &QPushButton::clicked, fTimerThreadStart);
    connect(fiveThread, &QThread::started, timerObject, &TimerThread::run);
    connect(timerObject, &TimerThread::workFinished, fiveThread, &QThread::quit);
    connect(fiveThread, &QThread::finished, fiveThread, &QThread::deleteLater);
Copy the code

The interface is also silky smooth. The specific business logic requirements can be rethought.