说明

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. CTE(With As)

    WITH tabdate(dt) AS ( FROM dual UNION ALL FROM tabdate WHERE dt ) SELECT * FROM TabDate ; 一.With Tab ...

  2. vue组件之间值传递四种方法汇总

    1.父组件获取子组件的数据和方法 $refs 子组件: <template> <div class="header"> <h3>{{ zz }} ...

  3. C#多线程(15):任务基础③

    目录 TaskAwaiter 延续的另一种方法 另一种创建任务的方法 实现一个支持同步和异步任务的类型 Task.FromCanceled() 如何在内部取消任务 Yield 关键字 补充知识点 任务 ...

  4. 4.K均值算法应用

    一.课堂练习 from sklearn.cluster import KMeans import matplotlib.pyplot as plt import numpy as np from sk ...

  5. ARP/RARP报文格式

    arp协议 地址解析协议ARP(Address Resolution Protocol)是用来将IP地址解析为MAC地址的协议. arp格式: 一个字节等于8位 硬件类型:指明发送方想知道的硬件接口类 ...

  6. QMessage自动定时关闭

    QMessageBox *box = new QMessageBox(QMessageBox::Information,tr("test"),tr("testtest&q ...

  7. [Inno Setup] 退出安装程序的两种方式

    1. 完全静默的退出 procedure ExitProcess(exitCode:integer); external 'ExitProcess@kernel32.dll stdcall'; ... ...

  8. Spring5参考指南:SpringAOP简介

    文章目录 AOP的概念 Spring AOP简介 Spring AOP通知类型 写过程序的都知道OOP即面向对象编程. 从最开始的面向过程编程,到后面的面向对象编程,程序的编写方式发生了重大的变化,面 ...

  9. 如何装双系统win10下装Ubuntu

    如何装双系统win10下装Ubuntu 第一步 制作启动盘 下载UItraISO软件.下载Ubuntu系统(地址:https://www.ubuntu.com/download).准备一个大于8g的U ...

  10. docker中安装nginx,部署前端代码

    最近在学习docker,初次接触,难免遇到磕磕碰碰,遂将其整理成博客,以便日后查看. 1.拉取nginx镜像 直接从官方镜像库拉取简单粗暴: docker pull nginx 2.运行 docker ...