QtConcurrent::run()多线程的同步、异步
Qt 提供了 QtConcurrent 模块,处理一些常见的并行计算,最大的特点就是无需再使用互斥锁这种很低级的操作,全都封装好了。除此以外,QFuture、QFutureWatcher、QFutureSynchronizer 类提供了一些辅助性的操作。参考:Qt 中的多线程技术 - 知乎 (zhihu.com)
【QtConcurrent::run() 需注意】
- 默认扔进了全局线程池,即 QThreadPool::globalInstance()
- 传参数的时候,都会复制一份副本。即使参数是引用,在函数中修改数据也不会对源对象产生任何影响。
- QFuture::result() 与 QFuture::waitForFinished()函数都会阻塞,直到结果可用才继续之后的代码。
- QtConcurrent::run()返回的QFuture不支持取消、暂停和进度报告。返回的QFuture只能用于查询运行/完成状态和函数的返回值。
可以执行无参、含参、有返回值函数,以及lambda表达式。参考Qt多线程编程之高级函数 - 知乎 (zhihu.com) 和 Qt 多线程的几种实现方式 - 知乎 (zhihu.com)
函数原型:
QFuture<T> QtConcurrent::run(Function function, ...)
QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
默认全局线程池。
【QFutureWatcher】
QFuture::result() 会阻塞,若不想一直等待结果,可以使用QFutureWatcher获取通知。
参考 QT高级线程API总结(一)QtConcrrent::run_qtconcurrent::run(qthreadpool::globalinstance(), [-CSDN博客
QByteArray bytearray = "hello ,world"; QFuture<QString > future = QtConcurrent::run(this, &MainWindow::threadFunc, bytearray); //QFutureWatcher<QString> *m_watcher = new QFutureWatcher<QString>(this); m_watcher = new QFutureWatcher<QString>(this); m_watcher->setFuture(future); connect(m_watcher, &QFutureWatcher<QString>::finished, [=](){ qDebug() << "finished"; }); QString MainWindow::threadFunc(QByteArray &arg){ qDebug() << "threadFunc:" << arg; //do process... return QString(""); };
【QFutureSynchronizer】
为了简化多个QFuture的同步等待操作,特地为我们提供了一个模板类QFutureSynchronizer。
参考 使用QFuture类监控异步计算的结果 - findumars - 博客园 (cnblogs.com)
#include <QCoreApplication> #include <QFuture> #include <QFutureSynchronizer> #include <QtConcurrent> #include <QDebug> //计算第lindex 个 斐波那契数值 qulonglong Fibonacci(int index) { qulonglong f1 = 1, f2 = 1, cur = 0; for(int i = 3; i <= index; i++) { cur = f1 + f2; f1 = f2; f2 = cur; } return cur; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QFutureSynchronizer<qulonglong> synchronizer; synchronizer.addFuture(QtConcurrent::run(Fibonacci, 50)); synchronizer.addFuture(QtConcurrent::run(Fibonacci, 100)); synchronizer.waitForFinished(); qDebug() << "第50个斐波那契数: " << synchronizer.futures()[0].result(); qDebug() << "第100个斐波那契数: " << synchronizer.futures()[1].result(); return a.exec(); }
【QThreadPool】
常用API如下:
/ 获取和设置线程中的最大线程个数 int maxThreadCount() const; void setMaxThreadCount(int maxThreadCount); // 给线程池添加任务, 任务是一个 QRunnable 类型的对象 // 如果线程池中没有空闲的线程了, 任务会放到任务队列中, 等待线程处理 void QThreadPool::start(QRunnable * runnable, int priority = 0); // 如果线程池中没有空闲的线程了, 直接返回值, 任务添加失败, 任务不会添加到任务队列中 bool QThreadPool::tryStart(QRunnable * runnable); // 线程池中被激活的线程的个数(正在工作的线程个数) int QThreadPool::activeThreadCount() const; // 尝试性的将某一个任务从线程池的任务队列中删除, 如果任务已经开始执行就无法删除了 bool QThreadPool::tryTake(QRunnable *runnable); // 将线程池中的任务队列里边没有开始处理的所有任务删除, 如果已经开始处理了就无法通过该函数删除了 void QThreadPool::clear(); // 在每个Qt应用程序中都有一个全局的线程池对象, 通过这个函数直接访问这个对象 static QThreadPool * QThreadPool::globalInstance();
参考 QT从入门到入土(五(2))——多线程(QtConcurrent::run())和线程池 转载 - 太空堡垒 - OSCHINA - 中文开源技术交流社区