QtConcurrent::run() 函数在单独的线程中运行一个函数,也就是说这是一种便捷的使用多线程的方法,实现异步运算。
使用QtConcurrent::run() 执行步骤如下:
#include
QtConcurrent::run()的原型很多,但是最基本的是以下 4 种,返回类型是QFuture,返回的结果在QFuture里面。
Function 是一个函数类型,由函数返回值和参数类型、个数决定。
异步运行,主要是为了防止一些耗时的运算会阻塞当前线程,QtConcurrent::run 的出现使得异步执行变得轻快
有一个耗时的计算过程 getCount()
void getCount(){ // 无参无返回值
int i = 0;
while (i < 3) {
qDebug() << i;
Sleep(1000); // 1000 ms
++i;
}
return;
}
同步运行会阻塞当前线程
#include
#include
#include
void getCount();
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start";
getCount (); // 耗时工作
qDebug() << "end";
return 0;
}
结果如下:当前的主线程被阻塞,等待getCout函数执行完毕,才结束
使用QtConcurrent::run() 异步执行
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start";
QtConcurrent::run( getCount );
qDebug() << "end";
return 0;
}
运行结果,如下图:
可见在异步执行中,主线程从头到尾运行完毕,完全没有被耗时的工作阻塞。
只要知道了 QtConcurrent::run() 原型,就可以很简单地调用,参数最多5个,如果多余5个,可用容器定义函数。
void getCount(int n){ // 有参无返回值
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000); // 1000 ms
++i;
}
return;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start";
QtConcurrent::run( getCount, 4 );
qDebug() << "end";
return 0;
}
// 截图略
QtConcurrent::run() 的返回值存在 QFuture 中,需要调用 QFuture 的成员函数来获取 。
谨记:QFuture 的结果查询函数,都是阻塞型的,他们都会等待 QtConcurrent::run() 结束。
QFuture 结果查询的函数 | |
---|---|
T result() const | resultAt(0),阻塞型 |
T resultAt(int index) const | 阻塞型 |
resultCount() const | 结果数量,如果不阻塞,返回值不准确 |
QList< T > results() const | 结果集合,阻塞型 |
修改上面的代码,如下:
int getCount(int n){ // 有参有返回
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000); // 300ms
++i;
}
return n;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start";
QFuture<int> f = QtConcurrent::run( getCount, 4 );
qDebug()<< f.result () << f.resultCount () ; // 会阻塞线程
qDebug() << "end";
return 0;
}
这么些,异步执行有啥意义呢?
QFuture 类本身未继承QObject,所以没法直接使用信号槽,所以需要另外一个监视类 QFutureWatcher。
使用步骤:
QFutureWatcher watcher;
watcher.setFuture(future);
connect(&watcher, &QFutureWatcher::finished ... );
代码如下:
#include
#include
#include
#include
#include
int getCount(int n){ // 有参有返回
qDebug() << "start" << QThread::currentThread ();
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000);
++i;
}
qDebug() << "end" << QThread::currentThread ();
return n;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start" << QThread::currentThread ();
QFuture<int> f = QtConcurrent::run( getCount, 4 );
QFutureWatcher<int> w;
w.setFuture (f);
QObject::connect (&w,&QFutureWatcher<int>::finished,[&]{
qDebug() << QThread::currentThread ();
qDebug()<< f.result () << f.resultCount () ;
a.quit (); // 主动退出,否则进程一直在循环
});
qDebug() << "end" << QThread::currentThread ();
return a.exec (); // 开启事件序列,等待信号槽的处理
}
结果如下:
用法大同小异,只要使用 QtConcurrent::run()的第三个原型函数即可。
代码:
#include
#include
#include
#include
class Test{ // 声明一个类
public:
int getCount(int n){
qDebug() << "start" << QThread::currentThread ();
int i = 0;
while (i < n) {
qDebug() << i;
Sleep(1000);
++i;
}
qDebug() << "end" << QThread::currentThread ();
return n;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "start" << QThread::currentThread ();
Test t; // 定义Test类对象
QFuture<int> f = QtConcurrent::run( &t,&Test::getCount, 4 );// 传入对象地址
QFutureWatcher<int> w;
w.setFuture (f);
QObject::connect (&w,&QFutureWatcher<int>::finished,[&]{
qDebug() << QThread::currentThread ();
qDebug()<< f.result () << f.resultCount () ;
a.quit (); // 主动退出,否则进程一直在循环
});
qDebug() << "end" << QThread::currentThread ();
return a.exec (); // 开启事件序列,等待信号槽的处理
}
代码结果和第5项一样,截图略。
如果函数有返回值,并用 QFuture 查询了返回值,这个操作会导致阻塞线程。