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 - 中文开源技术交流社区

posted @ 2023-12-09 19:17  夕西行  阅读(1519)  评论(0编辑  收藏  举报