alin的学习之路:Qt中的线程池QThreadPool

tech2022-07-15  155

alin的学习之路:Qt中的线程池QThreadPool

我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

// 通信函数 void* callback(void* arg) { read(); write(); return NULL; } // 比如: 套解析通信服务器端程序 int ld = socket(); // 绑定 bind(); // 监听 listen(); // 等待并且和多客户端建立连接 (和多个客户端建立连接并且通信) int fd[100]; int i = 0; while(1) { int fd[i] = accept(ld, NULL, NULL); // 阻塞函数 // 创建子线程 pthread_create(&tid, NULL, callback, &fd[i]); i++; } // 以上伪代码中服务器和客户端通信, 需要频繁的创建和销毁子线程, 效率比较低, 可以对其进行优化 // 优化方式: 可以通过线程池对创建的线程进行管理, 让创建的线程不停的工作, 不会频繁的对其创建和销毁

线程池的原理

/* 线程池的组成部分: 3块 1. 管理者线程 -> 1个 2. 工作的线程 (消费者角色) -> N个 3. 任务队列 线程池内部是如何工作的: 1. 线程池内部维护了一个任务队列, 因此提供了添加任务的函数, 将待处理的任务添加到线程池的任务队列中 2. 线程池内部维护了一个任务队列, 因此提供了获取任务的函数, 任务被处理之后就从任务队列中删除了 3. 线程池中维护了一定数量的线程, 他们的作用是是不停的读任务队列, 从里边取出任务并处理 - 如果任务队列为空, 将工作的线程阻塞 (使用条件变量/信号量阻塞) - 如果阻塞之后有了新的任务, 由生产者将阻塞解除, 工作线程开始工作 4. 管理者管理的就是工作的线程 - 管理者线程是不处理任务队列中的任务的 - 维护工作的线程的数量: - 线程池中默认工作的线程的创建 - 当任务过多的时候, 可以适当的创建一些新的工作线程 - 当任务过少的时候, 可以适当的销毁一些工作的线程 - 周期性的对任务队列中的任务数量, 和处理忙状态的工作线程个数进行检测 */

1. QRunnable

这个类的作用就是封装在线程池中执行的任务.

QRunnable 常用函数不多,主要是设置任务对象传给线程池后,是否需要自动析构。

Qt中需要添加到线程池的任务类必须继承 QRunnable,然后重写 run() 方法,才可以其传递给线程池

// 类的API // 在子类中必须要重写的函数, 里边是任务的处理流程 [pure virtual] void QRunnable::run(); // 参数设置为true: 这个任务对象在线程池中的线程中处理完毕, 这个任务对象就会自动销毁 // false: 这个任务对象在线程池中的线程中处理完毕, 对象需要程序猿手动销毁 void QRunnable::setAutoDelete(bool autoDelete); bool QRunnable::autoDelete() const;

2. QThreadPool

Qt中的 QThreadPool 类管理了一组 QThreads, 里边还维护了一个任务队列。

QThreadPool 管理和回收各个 QThread 对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局 QThreadPool 对象,可以通过调用 globalInstance() 来访问它。也可以单独创建一个 QThreadPool 对象使用。

相关API函数

int maxThreadCount() const; void setMaxThreadCount(int maxThreadCount); int expiryTimeout() const; void setExpiryTimeout(int expiryTimeout); // 给线程池添加任务, 任务是一个 QRunnable 类型的对象 // 如果线程池中没有空闲的线程了, 任务会放到任务队列中, 等待线程处理 void QThreadPool::start(QRunnable * runnable, int priority = 0); // 如果线程池中没有空闲的线程了, 直接返回值, 任务添加失败, 任务不会添加到任务队列中 bool QThreadPool::tryStart(QRunnable * runnable); // 线程池中被激活的线程的个数(正在工作的线程个数) int QThreadPool::activeThreadCount() const; // 尝试性的将某一个任务从线程池的任务队列中删除, 如果任务已经开始执行就无法删除了 bool QThreadPool::tryTake(QRunnable *runnable); // 将线程池中的任务队列里边没有开始处理的所有任务删除, 如果已经开始处理了就无法通过该函数删除了 void QThreadPool::clear(); bool QThreadPool::waitForDone(int msecs = -1); // 在每个Qt应用程序中都有一个全局的线程池对象, 通过这个函数直接访问这个对象 static QThreadPool * QThreadPool::globalInstance();
最新回复(0)