说明

Qt中可以有多种使用线程的方式:

  1. 继承 QThread,重写 run() 接口;
  2. 使用 moveToThread() 方法将 QObject 子类移至线程中,内部的所有使用信号槽的槽函数均在线程中执行;
  3. 使用 QThreadPool 线程池,搭配 QRunnable
  4. 使用 QtConcurrent

本文跳过第1和第2中方式,介绍后面两种

线程池

  • 创建和销毁线程需要和OS交互,少量线程影响不大,但是线程数量太大,势必会影响性能,使用线程池可以这种开销;
  • 线程池维护一定数量的线程,使用时,将指定函数传递给线程池,线程池会在线程中执行任务;

(一)QThreadPool和QRunnable

Qt中需要继承 QRunnable,重写 run() 方法,并,将其传递给线程池 QThreadPool 进行管理

QRunnable常用接口

bool QRunnable::autoDelete() const;
void QRunnable::setAutoDelete(bool autoDelete);
  • QRunnable 常用函数不多,主要设置其传到底给线程池后,是否需要自动析构;
  • 若该值为false,则需要程序员手动析构,要注意内存泄漏;

QThreadPool常用接口

void QThreadPool::start(QRunnable * runnable, int priority = 0);
bool QThreadPool::tryStart(QRunnable * runnable);
  • start() 预定一个线程用于执行QRunnable接口,当预定的线程数量超出线程池的最大线程数后,QRunnable接口将会进入队列,等有空闲线程后,再执行;
  • priority指定优先级
  • tryStart()start() 的不同之处在于,当没有空闲线程后,不进入队列,返回false
void QThreadPool::cancel(QRunnable * runnable);
void QThreadPool::clear();
  1. 如果,指定的QRunnable还没有执行,则从队列中移除
  2. 清空队列中还没有执行的QRunnable;
bool QThreadPool::waitForDone(int msecs = -1);
  • 等待所有线程结束并释放资源(如果需要自动释放的话);
  • msecs指定超时;
  • 若所有线程都被移除,则,返回true,否则返回false;
int	maxThreadCount() const
void setMaxThreadCount(int maxThreadCount)
  • 线程池维护的最大线程数量;
  • 设定该值,不会影响已经开始的线程;
  • 若没有设定,默认值是最大线程数,可以用:QThread::idealThreadCount(); 获取;
int	expiryTimeout() const
void setExpiryTimeout(int expiryTimeout)
  • 线程的终结超时;
  • 没有开启,且超过终结时间的线程,会退出,这些线程会根据需要重启开始,即这些线程不会消失,线程池会重新取出这些线程,开启或者放入队列,所谓的终结超时就是重新排列等待队列;
  • 建议在创建线程池后,调用 start() 前设定终结超时;
static QThreadPool * QThreadPool::globalInstance();
  • 全局内存池实例;
  • 若创建QThreadPool实例,则在实例生存周期内,内存池有效,

代码示例

//MyRunnable.h
class MyRunnable : public QRunnable
{
public:
MyRunnable(const QString& thread_name);
void run();
private:
QString threadName;
};
//MyRunnable.cpp
#include "myrunnable.h"
MyRunnable::MyRunnable(const QString &thread_name) : threadName(thread_name){}
void MyRunnable::run()
{
qDebug()<<"Start thread id:"<<QThread::currentThreadId();
int count = 0;
while(true)
{
if(count >= 10)
{
break;
}
qDebug()<<threadName<<" Count:"<<count++;
QThread::msleep(500);
}
}
//调用处
MyRunnable* my_runnable = new MyRunnable("1# thread");
my_runnable->setAutoDelete(true); MyRunnable* my_runnable_2 = new MyRunnable("2# thread");
my_runnable_2->setAutoDelete(true); threadPool.start(my_runnable);
threadPool.start(my_runnable_2);

(二)QtConcurrent

若有大量工作需要完成,则使用方式1、2、3均可,但是若只有一小段工作,需要在线程中完成,无论是使用QThread,还是moveToThread,更或者,使用QThreadPool,都有大材小用的感觉,这时候,使用 QtConcurrent 就是最佳选择

下面的说明,以Qt自带的例子为基础,并加入部分修改,例子目录:..\Qt\Qt5.5.1_mingw\Examples\Qt-5.5\qtconcurrent\runfunction

pro文件中添加模块

QT += concurrent

代码示例:

QString hello(QString name)
{
qDebug() << "Hello" << name << "from" << QThread::currentThread();
return name;
}
//掉用处
QFuture<QString> f1 = QtConcurrent::run(hello, QString("Alice"));
QFuture<QString> f2 = QtConcurrent::run(&threadPool, hello, QString("Bob"));
f1.waitForFinished();
f2.waitForFinished(); qDebug()<<f1.result();
qDebug()<<f2.result();

输出如下:

Hello "Alice" from QThread(0x1b1562a8, name = "Thread (pooled)")
Hello "Bob" from QThread(0x1b156248, name = "Thread (pooled)")
"Alice"
"Bob"

(1)说明:

QFuture<T> QtConcurrent::run(Function function, ...);
//QtConcurrent::run(QThreadPool::globalInstance(), function, ...);
QFuture<T> QtConcurrent::run(QThreadPool * pool, Function function, ...);

QtConcurrent::run() 方法的第一个参数是线程池,可以指定线程池,若没有指定,则使用全局线程池;

(2)执行普通函数,并传参,获取返回值

参考上例

  • 将需要传递的参数依次跟在函数名后面;
  • 使用 QFuture<T>result() 方法获取返回值;

(3)执行非const成员函数

QFuture<QString> f1 = QtConcurrent::run(this, &MainWindow::Hello, QString("Alice"));
QFuture<QString> f2 = QtConcurrent::run(&threadPool, this, &MainWindow::Hello, QString("Bob"));
  • 线程池和传参以及返回值相同;
  • 既然是成员,则需要指定实例,且是非const,则可能需要修改成员,在函数名前传入实例指针或者实例的应用;

(4)执行const成员

// call 'QList<QByteArray>  QByteArray::split(char sep) const' in a separate thread
QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');
...
QList<QByteArray> result = future.result();

const成员不会使用非const成员,所以,传入指针/引用或或者形参并没有区别,上例中,就是传入了形参

Qt线程池的更多相关文章

  1. QT 线程池 + TCP 小试(一)线程池的简单实现

    *免分资源链接点击打开链接http://download.csdn.net/detail/goldenhawking/4492378 很久以前做过ACE + MFC/QT 的中轻量级线程池应用,大概就 ...

  2. QT 线程池 + TCP 小试(三)实现最终功能

    *免分资源链接点击打开链接http://download.csdn.net/detail/goldenhawking/4492378 有了TCP.线程池,我们就可以把他们连接起来.使用最简单的 QMa ...

  3. C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型

    1.模板类queue,包含头文件<queue>中,是一个FIFO队列. queue.push():在队列尾巴增加数据 queue.pop():移除队列头部数据 queue.font():获 ...

  4. Qt 线程池QThreadPool类、QRunnable类

    QThreadPool类 用来管理 QThreads.此类中的所有函数都是线程安全的. 主要属性: 1.activeThreadCount: 此属性表示线程池中的活动线程数,通过activeThrea ...

  5. Qt多线程-QThreadPool线程池与QRunnable

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThreadPool线程池与QRunnable     本文地址:https:/ ...

  6. Qt中的多线程与线程池浅析+实例

    1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...

  7. Qt 学习之路 :Qt 线程相关类

    希望上一章有关事件循环的内容还没有把你绕晕.本章将重新回到有关线程的相关内容上面来.在前面的章节我们了解了有关QThread类的简单使用.不过,Qt 提供的有关线程的类可不那么简单,否则的话我们也没必 ...

  8. C#线程池用法

    C#线程池用法 在C#编程语言中,使用线程池可以并行地处理工作,当强制线程和更新进度条时,会使用内建架构的ThreadPool类,为批处理使用多核结构,这里我们来看在C#编程语言中一些关于来自Syst ...

  9. Qt 线程基础

    (转自:http://my.oschina.net/laopiao/blog/88158) 何谓线程? 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据 ...

随机推荐

  1. day28作业

    import os import uuid import pickle from conf import settings class School: def __init__(self,name,a ...

  2. Q - QQpet exploratory park HDU - 1493 (概率DP)

    题目大意: 一共有61个位置,标记为0~60.其中有10个重要位置,分别为:5, 12, 22, 29, 33, 38, 42, 46, 50 and 55. 有一个筛子,一共6个面,标有1~6.摇到 ...

  3. OkHttp 优雅封装 OkHttps 之 回调线程魔变

    第一篇:OkHttp 优雅封装 HttpUtils 之 气海雪山初探 第二篇:OkHttp 优雅封装 HttpUtils 之 上传下载解密 简介 HttpUtils 从 v2.3.0 之后便重命名了, ...

  4. 前端学习笔记-JavaScript

    js引入方式: 1.嵌入js的方式:直接在页内的script标签内书写js功能代码. <script type="text/javascript">alert('hel ...

  5. 4. Object

    1. Object.is( );  //用来判断,不同等 == 与===接近.NaN作出的调整 let obj={a:1,b:2}; Object.is(obj,obj);//true Object. ...

  6. 【启蒙】C笔记之初学阶段(下篇)

    下篇继续点赞,谢谢老铁,不存在下次一定的哈! c语言简单判断质数的方法 int isprime(int a){ ) ; ==||a==||a==) ; else { ;i<=sqrt(a);i+ ...

  7. Springboot:thymeleaf模板(八)

    存放位置:resources\templates 访问方式:通过Controller请求访问,不可直接访问(相当于web项目的WEB-INF目录) 环境依赖: <!--thymeleaf模板支持 ...

  8. SpringCloud(二)笔记之Eureka

    Eureka包含两个组件:Eureka Server和Eureka Client Eureka Server:提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册 Eureka ...

  9. 【高频 Redis 面试题】Redis 事务是否具备原子性?

    一.Redis 事务的实现原理 一个事务从开始到结束通常会经历以下三个阶段: 1.事务开始 客户端发送 MULTI 命令,服务器执行 MULTI 命令逻辑. 服务器会在客户端状态(redisClien ...

  10. linq详细案例

    LINQ to SQL语句(1)之Where 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句.Where操 ...