Qt并发编程
QtConcurrent命名空间提供了高级api,使编写多线程程序成为可能,而无需使用低级线程原语,如互斥锁、读写锁、等待条件或信号量。用QtConcurrent编写的程序会根据可用处理器内核的数量自动调整所使用的线程数。这意味着今天编写的应用程序在未来部署到多核系统时将继续可扩展。
QtConcurrent包括用于并行列表处理的函数式编程风格api,包括用于共享内存(非分布式)系统的MapReduce和FilterReduce实现,以及在GUI应用程序中管理异步计算的类:
map函数
map函数将函数应用到容器中的每个项,并就地修改项。
函数有两个参数,第一个参数是一个集合,第二个参数是一个函数,且需要为静态函数
#include <QList>
#include <QThread>
#include <QDebug>
#include <QGuiApplication>
#include <qtconcurrentmap.h>
#include <functional>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
std::function<void(int)> calculate_function = [](int value) -> void
{
qDebug() << QThread::currentThreadId() << value;
};
QList<int> array = { 1 ,3 ,5 ,7 };
QFuture<void> f = QtConcurrent::map(array,calculate_function);
f.waitForFinished();
return 0;
}
mapped
mapped函数与map类似,只是会将函数返回值返回到一个新的容器中
#include <QList>
#include <QThread>
#include <QDebug>
#include <QGuiApplication>
#include <qtconcurrentmap.h>
#include <functional>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
std::function<int(int)> calculate_function = [](int value) -> int
{
qDebug() << QThread::currentThreadId() << value;
return value + qrand();
};
QList<int> array = { 1 ,3 ,5 ,7 };
QFuture<int> f = QtConcurrent::mapped(array,calculate_function);
f.waitForFinished();
qDebug() << f.results();
return 0;
}
mappedReduced
mappedReduced函数一共有三个参数,可参看QtConcurrent Word Count Example的例子进行学习。
#include <QList>
#include <QThread>
#include <QDebug>
#include <QGuiApplication>
#include <qtconcurrentmap.h>
#include <functional>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
std::function<int(int)> calculate_function = [](int value) -> int
{
qDebug() << QThread::currentThreadId() << value;
return value;
};
//第二个参数需要限定为const ,每次执行完calculate_function后会将前一个次执行的结果和后一次执行的结果相加
std::function<void(int&,const int&)> calculate_function2 = [](int& value,const int& result) -> void
{
value += result;
};
QList<int> array = { 1 ,3 ,5 ,7 };
QFuture<int> f = QtConcurrent::mappedReduced<int>(array,calculate_function,calculate_function2);
f.waitForFinished();
qDebug() << f.results();
return 0;
}
简单的示例
class widget : public QWidget
{
public:
widget(){
layout = new QGridLayout;
QHBoxLayout *h = new QHBoxLayout(this);
QPushButton *btn = new QPushButton("open");
h->addLayout(layout,9);
h->addWidget(btn);
connect(btn,&QPushButton::clicked,this,&widget::open);
}
~widget(){}
public slots:
void open() {
//获取图像路径,作为map第一个参数的容器
QStringList files =QFileDialog::getOpenFileNames(this,"Select one or more files to open","./","Images (*.png *.xpm *.jpg)");
if(files.isEmpty()) return;
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0)
{
layout->removeWidget(child->widget());
child->widget()->setParent(0);
delete child;
}
qDeleteAll(labels);
labels.clear();
for (int i =0;i < files.count(); i++) {
QLabel *imageLabel = new QLabel;
imageLabel->setFixedSize(50,50);
layout->addWidget(imageLabel,i % 6, i /6);
labels.append(imageLabel);
}
//map函数第二个参数,通过线程进行异步加载
std::function<QImage(const QString&)> scale = [](const QString &imageFileName) {
QImage image(imageFileName);
qDebug() << QThread::currentThreadId();
return image.scaled(QSize(50, 50), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
};
static QFutureWatcher<QImage> futureWatcher;
futureWatcher.setFuture(QtConcurrent::mapped(files, scale));
connect(&futureWatcher, &QFutureWatcher<QImage>::resultReadyAt, [=](int num){
labels[num]->setPixmap(QPixmap::fromImage(futureWatcher.resultAt(num)));
});
connect(&futureWatcher, &QFutureWatcher<QImage>::finished, [=](){
qDebug() << "finish";
});
futureWatcher.waitForFinished();
}
private:
QList<QLabel*> labels;
QGridLayout *layout;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
widget w;
w.show();
app.exec();
}