Qt 之 Concurrent 4、【例】并发函数Run用法示例

文章目录

  • 1、QtConcurrent::run() 原型
  • 2、同步和异步的效果对比
  • 3、传递参数
  • 4、获取返回值
  • 5、使用QFutureWatcher的信号槽
  • 6、调用成员函数
  • 总结

QtConcurrent::run

QtConcurrent::run() 函数在单独的线程中运行一个函数,也就是说这是一种便捷的使用多线程的方法,实现异步运算。

使用QtConcurrent::run() 执行步骤如下:

  • 添加模块 QT += concurrent
  • 添加头文件 #include
  • 调用 QtConcurrent::run() 函数

1、QtConcurrent::run() 原型

QtConcurrent::run()的原型很多,但是最基本的是以下 4 种,返回类型是QFuture,返回的结果在QFuture里面。

  • QFuture< T > run( Function function ),无参
  • QFuture< T > run( Function function, const Arg1 &arg1 ⋯ \cdots const Arg5 &arg5),有参,参数最多5个
  • QFuture< T > run( const Class *object, Function function ⋯ \cdots ) 成员函数
  • QFuture< T > run(QThreadPool *pool, const Class *object, Function function ⋯ \cdots ) 指定 QThreadPool 的成员函数

Function 是一个函数类型,由函数返回值和参数类型、个数决定。

2、同步和异步的效果对比

异步运行,主要是为了防止一些耗时的运算会阻塞当前线程,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函数执行完毕,才结束

    Qt 之 Concurrent 4、【例】并发函数Run用法示例_第1张图片

  • 使用QtConcurrent::run() 异步执行

    • 添加模块 QT += concurrent
    • 添加头文件 #include
    • 在main 里 调用 QtConcurrent::run()
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      qDebug() << "start";
      QtConcurrent::run( getCount );
      qDebug() << "end";
      return 0;
    }
    

    运行结果,如下图:

Qt 之 Concurrent 4、【例】并发函数Run用法示例_第2张图片

可见在异步执行中,主线程从头到尾运行完毕,完全没有被耗时的工作阻塞。

3、传递参数

只要知道了 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;
}
// 截图略

4、获取返回值

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;
}

这么些,异步执行有啥意义呢?

5、使用QFutureWatcher的信号槽

QFuture 类本身未继承QObject,所以没法直接使用信号槽,所以需要另外一个监视类 QFutureWatcher。

使用步骤:

  1. 定义QFutureWatcher
    QFutureWatcher watcher;
  2. 设置监视对象 QFuture
    watcher.setFuture(future);
  3. 使用QFutureWatcher信号槽
    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 ();   // 开启事件序列,等待信号槽的处理
}

结果如下:

Qt 之 Concurrent 4、【例】并发函数Run用法示例_第3张图片

6、调用成员函数

用法大同小异,只要使用 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 查询了返回值,这个操作会导致阻塞线程。

你可能感兴趣的:(#,Qt,并发)