QtConcurrent多线程 – run()与QFuture

Qt中的 Concurrent 模块,为我们提供高级的(high-level)API 编写多线程程序,而不用使用低级的(low-level)线程元语(如互斥锁、读写锁、信号量、条件变量等)。

使用的时候需要在.pro文件中添加 concurrent 模块

我们首先来介绍一下 QtConcurrent 中最简单的使用方法 run()


1. run()函数

Concurrent::run() 表示在一个单独的线程中执行函数。

它的基本原型如下:
QFuture QtConcurrent::run(QThreadPool *pool, Function function, …)

  • 参数 function : 表示要在线程中执行的函数。
  • 参数 pool :线程池。表示从线程池中获取一个线程来执行该函数。
  • 注意 :函数可能不会立即执行;一旦线程池中的线程有可用的线程时,才会被执行。
  • 返回值 :返回一个 QFuture\<T> 对象。后面会详细说明。

关于Qt中线程池的使用,可以参考:Qt中的线程池QThreadPool

而我们更为常用的函数是下面的这个:
QFuture QtConcurrent::run(Function function, …)
它等价于:
QtConcurrent::run(QThreadPool::globalInstance(), function, …);
表示从全局的线程池中,获取线程。

关于 function 的说明:

  1. 函数的参数,只是做简单的值传递,比如下面的例子:

在调用 run() 的时候,这些值会被传递给执行函数,之后修改这些变量的值, 比如重新设置 integer 的值,并不会对计算产生影响。

  1. 可以为普通函数、类的成员函数、仿函数、lambda表达式。

调用const的成员函数

调用non-const成员函数

使用lambda表达式:


2. QFuture

QFuture 用来表示异步计算的结果。 QFuture 可以表示一段时间之后的异步计算的结果,使用它可以获取和控制当前计算的状态并获取计算完毕之后的结果。
下面是一个简单的例子:

QFuture 常用的函数有:

  1. 获取结果相关函数: result() 。该函数会判断结果是否为可用的,如果不可用则阻塞等待。如果可用则直接把结果返回。
  2. 设置运行状态函数: cancel() 表示取消,pause() 暂停,Resumes() 恢复,这些函数在 run() 这种模式下无效。
  3. 获取运行状态函数: isCanceled()isStarted()isFinished()isRunning()isPaused()
  4. 进度信息: progressValue()progressMinimum()progressMaximum()progressText() ,在 run() 模式下,这些值并没有正真的意义。waitForFinished() 会阻塞等待计算的完成,直到结果为可用的状态。

这里要注意的是,QFuture\<T> 模板 T 这个类型,需要有默认构造和拷贝构造。同时 QFuture 是一个基于引用计数的轻量级的类。
我们通常想要通过信号和槽的函数,异步的监控这些状态信息。这就需要 QFutureWatcher 这个类。


3. QFutureWatcher

QFutureWatcher 使我们通过信号和槽的方式,监控 QFuture 对象。
下面是一个示例:

函数 setFuture 表示设置被监控的 QFuture 对象,为了避免我们设置后不能及时的收到 QFuture 对象发送的信号,可以在执行 run 之前设置信号和槽的连接。
QFuture 对象的结果可用的时候, finished 信号会被 QFutureWatcher 发送。


下面是一个关于 run 使用的简单示例,在单独的线程中计算数值,异步通知GUI线程,这样GUI线程就不用阻塞等待计算结果的完成。效果如下:

QtConcurrent
这是一个计算前N个数和的示例,开启单独线程异步计算。
为了防止计算的太快,我这里故意在计算函数中加了延时:

完整代码如下:
头文件:

cpp文件:

You May Also Like

About the Author: admin

喜欢编程、爱游戏,更爱生活。

发表评论

电子邮件地址不会被公开。