QT异步编程之线程池QThreadPool

发布于:2025-03-01 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、概述

         在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建线程并销毁线程的过程势必会消耗内存。QThreadPool是Qt框架中用于管理线程池的类。它提供了一种高效的方式来管理和重用线程,从而减少线程创建和线程的开销。

二、QThreadPool的核心功能

1、线程重用:QThreadPool维护一组线程,任务完成后线程不会被销毁,而是保留在线程池中等待下一个任务。

2、任务队列:当所有线程都在忙碌时,新任务会被放入队列中,等待线程空闲处理。

3、自动扩展和收缩:根据任务数量动态调整线程池中的线程数量。

4、全局线程池:Qt提供了一个全局的QThreadPool实例,可以通过QThreadPool::globalInstance()访问。

三、QThreadPool的主要方法

1、void start(QRunnable *runnable, int priority = 0);

将任务(QRunnable对象)添加到线程池中执行 

2、bool tryStart(QRunnable *runnable);

尝试立即执行任务。如果没有可以线程,返回false 

3、 bool waitForDone(int msecs = -1);

阻塞当前线程,直到所有任务完成 

4、void setMaxThreadCount(int maxThreadCount); 

设置线程池最大线程池数 

5、 int activeThreadCount() const;

返回当前正执行任务的线程数 

6、 static QThreadPool *globalInstance(); 

返回全局的QThreadPool实例 

7、 void setExpiryTimeout(int expiryTimeout);

设置线程池中线程的过期时间(以毫秒为单位),当一个线程在指定时间内没有执行任务时,线程池会将该线程销毁,以减少资源占用。如果为负值(默认),则新创建的线程不会过期,即在线程池销毁之前,线程不会退出。

8、  void clear();

 清楚线程池,从队列中移除尚未启动的runnable

四、QRunnable类

        QThreadPool的任务是通过QRunnable对象表示的。QRunnable是一个抽象基类,需要继承它并实现run()方法来定义任务的具体逻辑。 

1、 virtual void run() = 0;

纯虚函数,子类必须实现。定义任务的具体逻辑

2、 void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; }

设置任务完成后是否自动删除,默认值为true。这个标志必须在调用QThread::strart()之前设置。在之后调用将出现未定义行为。

3、 bool autoDelete() const { return ref != -1; }

返回任务是否自动删除 

五、使用QThreadPool的步骤

1、创建任务:继承QRunnable并实现run()方法

// 自定义任务类
class MyTask : public QRunnable
{
public:
    MyTask(int id) : m_id(id) {}

    void run() override {
        qDebug() << "Task" << m_id << "started in thread" << QThread::currentThreadId();
        QThread::sleep(2); // 模拟耗时操作
        qDebug() << "Task" << m_id << "finished in thread" << QThread::currentThreadId();
    }

private:
    int m_id;
};

2、将任务提交到线程池:使用QThreadPool::start()

    // 获取全局线程池
    QThreadPool* pool = QThreadPool::globalInstance();

    // 设置线程池的最大线程数
    pool->setMaxThreadCount(3);

    // 创建并提交任务
    for (int i = 0; i < 10; ++i) 
    {
        MyTask* task = new MyTask(i);
        pool->start(task);
    }

3、等待任务完成(可选):使用QThreadPool::waitForDone()阻塞当前线程,直到所有任务完成 

    // 等待所有任务完成
    qDebug() << "Waiting for tasks to finish...";
    pool->waitForDone();
    qDebug() << "All tasks finished!";

 六、完整代码

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>

// 自定义任务类
class MyTask : public QRunnable
{
public:
    MyTask(int id) : m_id(id) {}

    void run() override {
        qDebug() << "Task" << m_id << "started in thread" << QThread::currentThreadId();
        QThread::sleep(2); // 模拟耗时操作
        qDebug() << "Task" << m_id << "finished in thread" << QThread::currentThreadId();
    }

private:
    int m_id;
};

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

    // 获取全局线程池
    QThreadPool* pool = QThreadPool::globalInstance();

    // 设置线程池的最大线程数
    pool->setMaxThreadCount(3);

    // 创建并提交任务
    for (int i = 0; i < 10; ++i) {
        MyTask* task = new MyTask(i);
        pool->start(task);
    }

    // 等待所有任务完成
    qDebug() << "Waiting for tasks to finish...";
    pool->waitForDone();
    qDebug() << "All tasks finished!";

    return 0;
}

 七、运行结果

Task 0 started in thread 0x1a34
Task 1 started in thread 0x1a38
Task 2 started in thread 0x1a3c
Task 0 finished in thread 0x1a34
Task 3 started in thread 0x1a34
Task 1 finished in thread 0x1a38
Task 4 started in thread 0x1a38
Task 2 finished in thread 0x1a3c
Task 5 started in thread 0x1a3c
...
All tasks finished!

说明:线程池最多同时运行三个任务。当一个任务完成后,线程池会立即从队列中取出下一个任务执行。

八、注意事项

1、任务的生命周期

(1)如果QRunnable的autoDelete()为true(默认值),任务完成后会自动删除。

(2)如果需要在任务完成后手动管理内存,可以将autoDelete()设置为false。

2、线程池的大小

(1)默认情况下,QThreadPool的最大线程数为CPU核心数。

(2)可以通过setMaxThreadCount()调整线程池大小

九、总结

1、QThreadPool是Qt中用于管理线程池的类,适合处理大量短期的任务

2、通过QRunnable定义任务逻辑,并使用QThreadPool提交任务

3、可以设置线程池大小、等待任务完成,并管理任务的生命周期