Qt线程池——QThreadPool详细说明

总结了两篇关于Qt线程的文章,刚想起来,还有线程池也属于线程知识相关。所以又补充一篇。

QThreadPool是Qt框架中的一个组件,它主要用于管理和复用线程资源,以优化并发任务的执行效率。当你有大量短小的任务需要异步执行时,使用QThreadPool可以避免频繁创建和销毁线程所带来的开销,并能轻松控制同时运行的任务数量。

QThreadPool的工作原理:

  • 线程管理:

    • QThreadPool维护了一个可复用的线程列表。
    • 当有新的QRunnable任务提交到线程池时,线程池会选择一个可用(即未执行任务)的线程来执行任务,如果没有可用线程并且线程总数没有达到预设的最大线程数,那么线程池将会创建一个新的线程来执行任务。
  • 任务调度:

    • 提交到线程池的任务必须是QRunnable的子类实例,每个任务都需要重写run()虚函数,其中包含实际的执行逻辑。
    • QThreadPool按照先进先出(FIFO)的原则处理任务,除非任务优先级不同,高优先级的任务可能会提前执行。
  • 线程限制:

    • 开发者可以调用QThreadPool::setMaxThreadCount(int maxThreadCount)来设置线程池允许的最大线程数量,超过此数量的任务将排队等待。

使用QThreadPool的步骤与示例代码:

以下是一个简单的QThreadPool使用示例:

cpp 复制代码
#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>
#include <QRunnable>

class MyTask : public QRunnable {
public:
    void run() override {
        qDebug() << "Task is running on thread:" << QThread::currentThreadId();
        // 这里放置具体任务执行的代码
        // ...
        // 假设这是一个耗时操作
        QThread::sleep(1);
        qDebug() << "Task finished.";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QThreadPool pool;

    // 设置最大线程数(如果不设置,默认不限制线程数量)
    pool.setMaxThreadCount(4);

    for (int i = 0; i < 10; ++i) {
        // 创建任务实例
        MyTask *task = new MyTask;
        
        // 提交任务到线程池
        pool.start(task);

        // 因为task的autoDelete属性为默认值(true),所以任务完成后,QThreadPool会自动删除任务对象
    }

    // 等待所有任务完成
    pool.waitForDone();

    return app.exec();
}

在这个例子中,我们定义了一个名为MyTask的类,它继承自QRunnable并重写了run()方法。然后我们创建了10个这样的任务实例,并提交到线程池中执行。由于设置了最大线程数为4,所以最多只有4个任务会并行执行,其余任务会在队列中等待直到有线程空闲。最后,我们调用waitForDone()来确保所有的任务都已完成再退出主程序。

QRunnable与QThread的对比说明

上边例子中出现了QRunnable的使用。特此对比QThread做一下补充说明。

QRunnable和QThread都是Qt库中用于实现多线程的工具,它们各自有特定的设计目标和使用场景,下面是对两者之间对比的详细说明:

QThread:

  • QThread是一个跨平台的线程类,它是QObject的一个子类,因此可以和其他QObject一样使用信号和槽进行通信,这是QThread的一大优势。
  • 使用QThread一般有两种方式:一是通过继承QThread类并重写run()方法,然后调用start()启动线程;二是将工作逻辑封装在另外的QObject中,并将这个QObject移动到新创建的QThread实例的事件循环中,这样工作逻辑将在新线程的上下文中执行。
  • 当你继承QThread并重写run()方法时,实际上是在创建一个具有自己事件循环的线程,这种情况下线程不会在run()方法执行完毕后立即结束,而是会继续监听事件队列。
  • QThread适合长时间运行或者需要持续存在并可能随时处理事件的线程,例如后台服务、定时器等。

QRunnable:

QRunnable是一个轻量级的非QObject类,设计初衷是为了简化临时性、一次性任务的执行,不需要像QThread那样建立完整的对象层次结构。

  • QRunnable只包含一个纯虚函数void run(),你需要继承QRunnable并实现这个run()函数,用来定义线程的具体工作内容。
  • QRunnable配合QThreadPool使用可以实现任务的并发执行。线程池负责调度和管理线程资源,当一个QRunnable任务提交给线程池时,池中的一个线程会执行该任务的run()方法,完成后线程将回到池中等待下一个任务。
  • QRunnable不适合需要长期存在的线程,因为它不支持信号和槽机制,这意味着无法像QThread那样直接在线程间发送信号来同步数据或通知事件。
  • QRunnable更适合执行短暂、独立、计算密集型的任务,特别是当任务数量巨大且可以很好地并行化时,通过QThreadPool能够有效地利用系统资源。

总结来说,QThread更适合构建复杂的多线程应用,特别是在需要使用信号槽机制来协调线程间交互的情况下;而QRunnable则更适合处理一次性、无状态、易于并行化的任务,它可以高效地利用线程池,减少系统资源消耗并提高并发性能。

相关推荐
C++ 老炮儿的技术栈3 小时前
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
c语言·开发语言·c++·qt·算法
名誉寒冰6 小时前
# KVstorageBaseRaft-cpp 项目 RPC 模块源码学习
qt·学习·rpc
xiaoyaoyou.xyz7 小时前
嵌入式Linux Qt开发:1、搭建基于ubuntu18.04的Qt开发环境及测试(解决Qt creator输入法问题)
linux·qt
小龙Guo10 小时前
QT+opencv实现卡尺工具找圆、拟合圆
开发语言·qt·opencv
破晓的历程12 小时前
Qt之Qfile类
开发语言·qt
feiyangqingyun15 小时前
Qt/C++开发监控GB28181系统/录像文件查询/录像回放/倍速播放/录像文件下载
c++·qt·gb28181·录像回放·录像文件下载
忆源17 小时前
【Qt】之音视频编程2:QtAV的使用篇
开发语言·qt·音视频
enyp8018 小时前
Qt原型模式实现与应用
开发语言·qt·原型模式
忆源1 天前
【Qt】之音视频编程1:QtAV的背景和安装篇
开发语言·qt·音视频
teacher伟大光荣且正确1 天前
Qt Creator 配置 Android 编译环境
android·开发语言·qt