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

本文详细介绍了 QtConcurrent::run 函数的多种用法,包括同步与异步效果对比、参数传递、返回值获取及配合 QFutureWatcher 的使用等,并通过实例展示了如何调用成员函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QtConcurrent::run

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

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

  • 添加模块 QT += concurrent
  • 添加头文件 #include <QtConcurrent>
  • 调用 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 <QApplication>
    #include <QDebug>
    #include <windows.h>
    
    void getCount();
    
    int main(int argc, char *argv[])
    {
      QApplication a(argc, argv);
      qDebug() << "start";
      getCount ();  // 耗时工作
      qDebug() << "end";
      return 0;
    }
    

    结果如下:当前的主线程被阻塞,等待getCout函数执行完毕,才结束

    image-20210610111459756

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

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

    运行结果,如下图:

image-20210610112339741

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

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() constresultAt(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<int> watcher;
  2. 设置监视对象 QFuture
    watcher.setFuture(future);
  3. 使用QFutureWatcher信号槽
    connect(&watcher, &QFutureWatcher<int>::finished ... );

代码如下:

#include <QApplication>
#include <QDebug>
#include <windows.h>
#include <QtConcurrent>
#include <QFutureWatcher>

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 ();   // 开启事件序列,等待信号槽的处理
}

结果如下:

image-20210610124633412

6、调用成员函数

用法大同小异,只要使用 QtConcurrent::run()的第三个原型函数即可。

代码:

#include <QApplication>
#include <windows.h>
#include <QtConcurrent>
#include <QtCore>

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 Concurrent 使用教程 #### 并发编程基础 Qt Concurrent 提供了一组高层次的接口用于并行计算,简化了多线程程序的设计。该模块主要围绕 `QtConcurrent::run` 函数展开,允许异步运行函数而无需显式创建线程对象[^1]。 #### 与信号槽机制集成 通过使用 `QFutureWatcher` 类,可以方便地监控由 `QtConcurrent::run` 启动的任务的状态变化,并连接到 UI 组件上实现交互反馈。如: - 当任务完成时会触发 `finished()` 信号; - 进度改变则发出 `progressValueChanged(int)` 信号以便于更新进度显示; 这些特性使得开发者能够轻松构建响应式的图形化应用程序界面[^2]。 #### 错误处理策略 尽管 QtConcurrent 自身并未提供专门针对错误的通知方式,但仍可通过其他手段来进行有效的异常捕捉和恢复工作。具体来说就是利用 `QFuture` 对象配合 try-catch 结构,在适当位置插入断点检查可能发生的失败情况。 #### 枚举类型介绍 为了更好地控制并发行为以及获取更详细的执行信息,Qt 引入了一些有用的枚举定义: - **任务状态**:如 `QFuture::Running`, `QFuture::Finished` 等描述当前作业所处阶段; - **归约选项**:像 `QtConcurrent::OrderedReduce` 或者 `QtConcurrent::UnorderedReduce` 则决定了数据聚合过程中元素间的相对次序关系。 #### 示例代码展示 下面给出一段简单的 Python 风格伪代码来说明如何运用上述概念编写基于 Qt并发应用逻辑: ```cpp #include <QtConcurrent/QtConcurrent> #include <QFutureWatcher> void startTask() { auto future = QtConcurrent::run([](){ // 执行耗时操作... return result; }); QFutureWatcher<int> watcher; QObject::connect(&watcher, &QFutureWatcherBase::finished, [](){ qDebug() << "任务已完成"; }); watcher.setFuture(future); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值