QtConcurrent thread usage instructions

Regarding Qt Concurrent, let's first take a look at how Qt Assitant is described.

The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores. Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.

To put it simply, when we use QtConcurrent to implement multi-threading, we do not need to consider the protection of shared data. Moreover, it can automatically optimize the number of threads based on the CPU's capabilities.

QtConcurrent mainly provides three methods to implement multi-threading, namely: run, map, and filter. The usage methods are explained in detail below.

As a benefit for this article, you can receive a Qt development learning package and technical videos for free , including (Qt practical projects, C++ language basics, C++ design patterns, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project practice, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the article to receive the fee↓↓

Table of contents

  • Concurrent run starts a thread in the thread pool to execute a function.
  • Concurrent map is used to process a batch of data in parallel.
  • Concurrent Filter, as the name suggests, is generally used to filter a batch of data.

Concurrent run starts a thread in the thread pool to execute a function. Basic usage is as follows:

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);
//std::thread 实现
std::thread thread = std::thread(aFunction);
thread.detach();

As above, the thread of the standard library can also achieve the same function. The difference is that the thread implemented by QtConcurrent can obtain the return value of the thread function.

extern QString functionReturningAString();
QFuture<QString> future = QtConcurrent::run(functionReturningAString);
...
QString result = future.result();

QtConcurrent::run() also provides the implementation of thread function parameter passing:

extern QString someFunction(const QByteArray &input);
QByteArray bytearray = ...;
QFuture<QString> future = QtConcurrent::run(someFunction, bytearray);
...
QString result = future.result();

In addition, like std::thread, QtConcurrent::run() also provides a member function to implement threads.

1) Call const function

QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');

or,

QFuture<QList<QByteArray> > future = QtConcurrent::run(&bytearray, &QByteArray::split, ',');

2) Call non-const functions

QImage image = ...;
QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);

Concurrent map is used to process a batch of data in parallel. It mainly includes three usages: map, mapped, and mappedReduced.

The map function is used in usage scenarios where the original data needs to be changed. The usage method is as follows:

void toUpper(QString &str)
{
    str = str.toUpper();
}
QStringList strWords;
strWords << "Apple" << "Banana" << "cow" << "dog" << "Egg";
auto future =  QtConcurrent::map(strWords, toUpper);
future.waitForFinished();
//strWords = {"APPLE", "BANANA", "COW", "DOG", "EGG"}

The mapped function is used in usage scenarios where the original data is not changed and the processing result is returned. How to use it:

QString toUpper(const QString &str)
{
    return str.toUpper();
}
QStringList strWords;
strWords << "Apple" << "Banana" << "cow" << "dog" << "Egg";
auto future =  QtConcurrent::mapped(strWords, toUpper);
future.waitForFinished();
qDebug() << future.results();
//输出:("APPLE", "BANANA", "COW", "DOG", "EGG")

mappedReduced is used in usage scenarios where mapped results need to be processed. How to use it:

QString toUpper(const QString &str)
{
    return str.toUpper();
}
void reduceFun(QList<QString> &dictionary, const QString &string)
{
    dictionary.push_back(QString("result: ") + string);
}
 
QStringList strWords;
strWords << "Apple" << "Banana" << "cow" << "dog" << "Egg";
auto future =  QtConcurrent::mappedReduced(strWords, toUpper, reduceFun);
future.waitForFinished();
qDebug() << future.result();
//输出:("result: BANANA", "result: APPLE", "result: COW", "result: DOG", "result: EGG")

Note that the order of the output results of the above code is different from the order of the original data. The logic of the mappedReduced function is to start multiple threads to execute toUper to process each element in the linked list, and the processed results are then handed over to the reduceFun function one by one for processing. reduceFun does not wait for all threads of toUper to finish executing before starting execution, and at the same time, only one reduceFun thread is executing. If you need to make the final output result sequence consistent with the input, you need to use the fourth parameter of the mappedReduced function and assign it to QtConcurrent::OrderedReduce to ensure that the sequence is consistent.

Similarly, Concurrent map also provides member functions as thread functions. The thread function must be a member function of the type of the element in the sequence. The following example is given in the Qt help documentation:

// Squeeze all strings in a QStringList.
QStringList strings = ...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);
 
// Swap the rgb values of all pixels on a list of images.
QList<QImage> images = ...;
QFuture<QImage> bgrImages = QtConcurrent::mapped(images, &QImage::rgbSwapped);
 
// Create a set of the lengths of all strings in a list.
QStringList strings = ...;
QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(strings, &QString::length, &QSet<int>::insert);

Concurrent maps can also use function objects. The following example is given in the Qt help documentation:

struct Scaled
{
    Scaled(int size): m_size(size) { }
    typedef QImage result_type;
 
    QImage operator()(const QImage &image)
    {
        return image.scaled(m_size, m_size);
    }
 
    int m_size;
};
 
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

Concurrent Filter, as the name suggests, is generally used to filter a batch of data. It also includes three usages: filter, filtered, and filteredReduce.

The filter function must be defined in the following form. The T type is consistent with the element type of the data processed. When false is returned, the corresponding elements are filtered out.

bool function(const T &t);

Similar to Concurrent Map, the filter function will change the original data, the filtered function will save the processing results in the return value of the filtered function, and filteredReduce will call the reduceFun function to process the filtered data. I won’t go into details here, you can refer to the usage of map function completely.

As a benefit for this article, you can receive a Qt development learning package and technical videos for free , including (Qt practical projects, C++ language basics, C++ design patterns, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project practice, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/m0_73443478/article/details/133133001