Qt - 多线程之并发(QtConcurrent)

一 什么是QtConcurrent?

Concurrent是并发的意思,而QtConcurrent同std一样,是一个命名空间(namespace)。提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。

对于QtConcurrent真正要学习的是该命名空间下定义的函数。下面要讲的就是QtConcurrent::run函数的使用方法。

二 QtConcurrent::run()

QT有几种可以实现多线程编程的方式,其中最方便使用,最便携的一定是QtConcurrent::run()了,这是一个模板函数,有很多的重载原型。

//在新的线程中调用普通函数 
template <typename T> QFuture<T> QtConcurrent::run(Function function, ...) 

//在新的线程里调用成员函数 有多个重载实现不同的参数个数 
template <typename T> QFuture<T> QtConcurrent::run(className *obejct, Function function, ...)

//使用线程池中的线程调用普通函数 
template <typename T> QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...) 

这些模板都有多个重载,支持带参数函数,切可以带多个参数。

QFuture 也是一个模板类,它可以监控线程的运行状态有,并可以获取在另一个线程中运行的函数的返回值,返回值通过调用result()函数获取。

需要注意的是获取返回值之前,最好先调用waitForFinished()保证线程执行完毕。

注意:使用QtConcurrent::run()需要在.pro文件中添加该模块并且包含头文件

.pro文件中添加:

QT       += concurrent

包含头文件:

#include <QtConcurrent>

 

三 QtConcurrent::run()运行示例

每调用一次QtConcurrent::run()函数,就新建立一个线程。

示例1:将普通函数运行在两个不同的线程中

#include <QString>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include "qtconcurrentrun.h"

QString func1()
{
	qDebug()<<"我是func2函数";
}
Qstring func2(QString name)
{
    qDebug() << name << "from" << QThread::currentThread();
}
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    
    QFuture<QString> fut1 = QtConcurrent::run(func1);// 1.用QFuture获取该函数的运行结果
    QFuture<QString> fut2 = QtConcurrent::run(func2, QString("Thread 1"));//2.参数2:向func函数传递的参数
	QString result1 = fut1.result();
	QString result2 = fut2.result();
    fut1.waitForFinished();
    fut2.waitForFinished();
} 

运行结果:

//输出结果如下:
"Thread 1" from QThread(0x1b74fd2ebc0, name = "Thread (pooled)")
"Thread 2" from QThread(0x1b74fd534e0, name = "Thread (pooled)") 

 

示例2:成员函数

  • 将类中的成员函数运行在某一个线程中,可将指向该类实例的 引用或指针 作为 QtConcurrent::run 的第一个参数传递进去;
  • 常量成员函数传递常量引用 (const reference),而非常量成员函数一般传递指针 (pointer)
#include <QString>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include "qtconcurrentrun.h"
class A
{
public:
   A()
   {
   	std::cout << "我是 A 的构造函数" << std::endl;
   };

   QString m_func(QString name)
   {
   	m_name = name; 
   	std::cout << "我是 A 的成员函数" << std::endl;
   }
   QString m_name;
};

int main(int argc, char **argv)
{
   QApplication app(argc, argv);
   QByteArray bytearray = "hello world";
	A *a = new A();
    QFuture<QString> fut2 = QtConcurrent::run(bytearray,&QByteArray::split,',');//1.调用QByteArray的常量成员函数split(),传递常量引用,bytearray
   QFuture<QByteArray> fut3 = QtConcurrent::run(a,&A::m_func, QString("Thread 2"));//2.非常量成员函数运行在一个新的线程,传递指针

   QString result2 = fut2.result();
   QString result3 = fut3.result();

   fut2.waitForFinished();
   fut3.waitForFinished();
} 

运行结果:

//输出结果如下:
"Thread 1" from QThread(0x1b74fd2ebc0, name = "Thread (pooled)")
"Thread 2" from QThread(0x1b74fd534e0, name = "Thread (pooled)") 

 

示例3:线程池的应用

如果要为其指定线程池,可以将线程池的指针作为第一个参数传递进去

#include <QString>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include "qtconcurrentrun.h"
using namespace QtConcurrent;
 
void func(QString name)
{
    qDebug() << name << "from" << QThread::currentThread();
}
 
int main(int argc, char **argv)
{
    QApplication app(argc, argv);
    QThreadPool pool;
    pool->setMaxThreadCount(QThreadPool::globalInstance()->maxThreadCount());//setMaxThreadCount设置最大线程数,maxThreadCount()获取该计算机可运行的线程数
    QFuture<void> fut1 = run(&pool,func, QString("Thread 1"));
    fut1.waitForFinished();
} 

 

 

总结

  1. 调用run() 之后,函数不一定会被立即执行,如果有多个run()被调用,函数的调用顺序不一定是run()的调用顺序,这些都和线程的调度有关系。
  2. run(function) 实际上等价于run(QThreadPool::globalInstance(),function)

如果只是简单的想在其他线程中调用某个函数,不需要复杂的数据同步,那么QtConcurrent::run() 相比其他实现多线程的方式绝对是不二之选。

 

posted @ 2023-10-25 11:43  [BORUTO]  阅读(2370)  评论(0编辑  收藏  举报