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

1. 介绍

线程的创建及销毁需要与系统交互,会产生很大的开销。若需要频繁的创建线程建议使用线程池,有线程池维护一定数量的线程,当需要进行多线程运算时将运算函数传递给线程池即可。线程池会根据可用线程进行任务安排。

2. QThreadPool

相关帮助文档:QThreadPool

此类为Qt提供的线程池函数,使用此类只需要配置线程池的最大线程数量、线程长时间不使用的过期时间等参数,不需要进行QThread相关的操作。

此类有两种使用方式:全局线程池和局部线程池。下面首先介绍两种类型后续介绍类提供的方法

2.1. 基本操作函数

  1. int activeThreadCount() const //当前的活动线程数量
  2. void clear()//清除所有当前排队但未开始运行的任务
  3. int expiryTimeout() const//线程长时间未使用将会自动退出节约资源,此函数返回等待时间
  4. int maxThreadCount() const//线程池可维护的最大线程数量
  5. void releaseThread()//释放被保留的线程
  6. void reserveThread()//保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
  7. void setExpiryTimeout(int expiryTimeout)//设置线程回收的等待时间
  8. void setMaxThreadCount(int maxThreadCount)//设置最大线程数量
  9. void setStackSize(uint stackSize)//此属性包含线程池工作线程的堆栈大小。
  10. uint stackSize() const//堆大小
  11. void start(QRunnable *runnable, int priority = 0)//加入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable ,后续介绍
  12. bool tryStart(QRunnable *runnable)//尝试启动一个
  13. bool tryTake(QRunnable *runnable)//删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
  14. bool waitForDone(int?<i>msecs</i>?=?-1)//等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出

QThread::idealThreadCount函数,会根据当前设备的硬件情况给出一个线程数量,而maxThreadCount的默认值就是此值。

setStackSize

只有在线程池创建新线程时才使用该属性的值。更改它对已经创建或运行的线程没有影响。默认值是0,这使得qthread使用操作系统默认的堆栈大小。

The value of the property is only used when the thread
pool creates new threads. Changing it has no effect for already created
or running threads.

The default value is 0, which makes QThread use the operating system default stack size.

maxThreadCount? reserveThread? activeThreadCount

由于reserveThread 后的线程不计入线程数量,因此可能出现activeThreadCount>maxThreadCount? 情况

Note: It is possible for this function to return a value that is greater than maxThreadCount(). See reserveThread() for more details.

2.2. start tryStart tryTake

对于start,传入的是QRunnable对象指针,传入后线程池会调用QRunnable的autoDelete() 函数,若返回true,则当此运算完成后自动释放内容,不需要后续主动判断是否运算完成并释放空间。

对于tryTake,若返回成功,不会自动释放内容,而是需要调用方主动释放,无论autodelete返回值是什么。返回false自然也不会自动delete

Attempts to remove the specified runnable from the queue if it is not yet started. If the runnable had not been started, returns true, and ownership of runnable is transferred to the caller (even when runnable->autoDelete() == true). Otherwise returns false.

Note: If runnable->autoDelete() == true, this function may remove the wrong runnable. This is known as the ABA problem: the original runnable
may already have executed and has since been deleted. The memory is
re-used for another runnable, which then gets removed instead of the
intended one. For this reason, we recommend calling this function only
for runnables that are not auto-deleting.

对于tryStart,若返回成功,等同于start,若false,则不会自动delete

注意,对于autoDelete必须在调用state/trytake之前进行修改,不要再调用以后修改,否则结果不可预测

Note that changing the auto-deletion on runnable after calling this function results in undefined behavior.

QRunnable的autoDelete默认返回true,若需要更改需要调用setAutoDelete进行更改

2.3. 全局线程池

QThreadPool提供了一个静态函数,globalInstance(),使用此方法可获取一个当前进程的全局线程池,可在多个类中共同使用一个线程池。

2.4. 局部线程池

和常规类的使用相同,可以通过? QThreadPool pool;的方式建立一个局部线程池,并由当前类维护,可保证此线程池仅供当前类应用

3. QRunnable

线程池每一个需要运行的任务均需要作为QRunnable的子类,并重写其run函数,帮助文档:http://doc.qt.io/qt-5/qrunnable.html

QRunnable只有run、autodelete、setautodelete这三个关键函数。

run内重写需要运算的内容。

autodelete用来标识是否在运行结束后自动由线程池释放空间,具体说明见上述“QThreadPool-基本操作函数-start tryStart tryTake”

4. 范例

4.1. 简单使用范例

  1. #include <QCoreApplication>
  2. #include <QThreadPool>
  3. #include <QThread>
  4. #include <QRunnable>
  5. #include <QDebug>
  6. class MyRun : public QRunnable {
  7. public:
  8. void run() {
  9. int i=3;
  10. while(i) {
  11. i--;
  12. qDebug()<<"thread start:"<<QThread::currentThreadId();
  13. QThread::msleep(500);
  14. }
  15. }
  16. };
  17. int main(int argc, char *argv[]) {
  18. QCoreApplication a(argc, argv);
  19. qDebug()<<"Main:"<<QThread::currentThreadId();
  20. QThreadPool m;
  21. MyRun *run=new MyRun;
  22. if(!run->autoDelete()) {
  23. qDebug()<<"QRunnable's autoDelete default value is not true";
  24. run->setAutoDelete(true);
  25. }
  26. qDebug()<<m.maxThreadCount()<<m.expiryTimeout();
  27. qDebug()<<m.activeThreadCount();
  28. m.start(run);
  29. qDebug()<<m.activeThreadCount();
  30. m.waitForDone();
  31. qDebug()<<m.activeThreadCount();
  32. return 0;
  33. }

结果:

  1. Main: 0xffc
  2. 4 30000
  3. 0
  4. 1
  5. thread start: 0x7e4
  6. thread start: 0x7e4
  7. thread start: 0x7e4
  8. 0

4.2. 全局线程池和局部线程池对比

  1. #include <QCoreApplication>
  2. #include <QThreadPool>
  3. #include <QThread>
  4. #include <QRunnable>
  5. #include <QDebug>
  6. class MyRun : public QRunnable {
  7. public:
  8. void run() {
  9. int i=3;
  10. while(i) {
  11. i--;
  12. qDebug()<<"thread start:"<<QThread::currentThreadId();
  13. QThread::msleep(500);
  14. }
  15. }
  16. };
  17. int main(int argc, char *argv[]) {
  18. QCoreApplication a(argc, argv);
  19. qDebug()<<"Main:"<<QThread::currentThreadId();
  20. QThreadPool pool;
  21. QThreadPool *global_pool = QThreadPool::globalInstance();
  22. MyRun *run=new MyRun;
  23. if(!run->autoDelete()) {
  24. qDebug()<<"QRunnable's autoDelete default value is not true";
  25. run->setAutoDelete(true);
  26. }
  27. pool.setMaxThreadCount(2);//修改了局部线程数量
  28. qDebug()<<"pool:"<<pool.maxThreadCount()<<pool.expiryTimeout()<<"\r\nglobal"<<global_pool->maxThreadCount();
  29. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  30. pool.start(run);
  31. global_pool->start(new MyRun);
  32. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  33. pool.waitForDone();
  34. global_pool->waitForDone();
  35. qDebug()<<pool.activeThreadCount()<<global_pool->activeThreadCount();
  36. return 0;
  37. }

结果

  1. Main: 0x30c4
  2. pool: 2 30000
  3. global 4
  4. 0 0
  5. 1 1
  6. thread start: 0x22d0
  7. thread start: 0xfe0
  8. thread start: 0x22d0
  9. thread start: 0xfe0
  10. thread start: 0x22d0
  11. thread start: 0xfe0
  12. 0 0

当建立局部线程池,修改其参数后仅供局部使用,不会影响全局线程池的。

转载请以链接形式标明本文标题和地址:Techie亮博客 » Qt多线程-QThreadPool线程池与QRunnable

Qt多线程-QThreadPool线程池与QRunnable的更多相关文章

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

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

  2. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  3. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  4. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

  5. 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

  6. ExecutorService 建立一个多线程的线程池的步骤

    ExecutorService 建立一个多线程的线程池的步骤: 线程池的作用: 线程池功能是限制在系统中运行的线程数. 依据系统的环境情况,能够自己主动或手动设置线程数量.达到执行的最佳效果:少了浪费 ...

  7. C#多线程和线程池问题

    static void Main(string[] args) { Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 threadA ...

  8. Java基础教程:多线程基础——线程池

    Java基础教程:多线程基础——线程池 线程池 在正常负载的情况瞎,通过为每一个请求创建一个新的线程来提供服务,从而实现更高的响应性. new Thread(runnable).start() 在生产 ...

  9. Python多线程、线程池及实际运用

    我们在写python爬虫的过程中,对于大量数据的抓取总是希望能获得更高的速度和效率,但由于网络请求的延迟.IO的限制,单线程的运行总是不能让人满意.因此有了多线程.异步协程等技术. 下面介绍一下pyt ...

随机推荐

  1. Python图形界面Tk

    最近在学习Python,在使用Tkinter做图形界面时遇到了几个小问题,网上查了一下,在Python2.x导入的是Tkinter,Python3则是tkinter.而且导入的simpledialog ...

  2. 解决Linux上tomcat启动却无法访问

    linux中tomcat的安装 安装tomcat前首先要安装对应的jdk并配置Java环境 下载tomcat安装包 下载路径:https://tomcat.apache.org/download-80 ...

  3. lncRNA芯片重注释

    .caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table ...

  4. # 20155222卢梓杰 2016-2017-2 《Java程序设计》第2周学习总结

    20155222卢梓杰 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 数据类型 所占字节数 short整数 2 int整数 4 long整数 8 float ...

  5. 20155226 2016-2017-2 《Java程序设计》第2周学习总结

    20155226 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 了解了基本类型以及初识类类型,熟悉了注释,变量及运算符的使用. 了解了几种运算方式但还不算熟 ...

  6. 学号20155311 2016-2017-2 《Java程序设计》第一次实验报告

    课程:Java程序设计 实验名称:Java开发环境的熟悉 实验目的与要求: 没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程: 完成实验. ...

  7. DSP5509项目之用FFT识别钢琴音调(5)之开始傅里叶变换

    1. 首先电脑上下载一个音频模拟的软件 2. 研究下钢琴的声音范围27HZ到4000HZ,那么采样频率需要是信号的两倍频率以上,所以建议采样频率是16KHZ.先看一下采集到的数据,如下是空载时候采集到 ...

  8. CI框架浅析(一)

            CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而“优雅”的工具包,它可以为开发者们建立功能完善的 Web 应用程序.本人使用CI框架有一段时间了,现在决定把 ...

  9. 前端 CDNJS 库及 Google Fonts、Ajax 和 Gravatar 国内加速服务

    由于某些众所周知的原因,好多开源的 JS 库采用的国外 CDN 托管方式在国内访问速度不如人意.所以我们特意制作了这个公益项目,托管了 CDNJS 的所有开源 JS 库以及反代了 Google Fon ...

  10. Electron小记

    一.安装 1.安装NodeJS 2.安装electronjs:npm install -g electron --unsafe-perm=true --allow-root 安装完,环境为: Node ...