在我们进行实际编程时,经常会碰到数量级大、耗时长的任务,尤其在网络服务中,可能有几万个用户同时访问你的服务器,不可能进来一个用户我们就开辟一个线程,这样做的后果是当用户量大的时候线程数量过多,线程间的调度效率就很低下了,反而会影响程序的效率。因此这时候,我们可以通过线程池,对一定数量的线程进行复用,提高应用的效率。线程池的结构是根据设计模式中的生产者消费者模式进行设计的,感兴趣的朋友可以百度学习一下。
这几天看了网上几篇的线程池实现代码,本篇文章主要参考以下博客内容:
https://www.jianshu.com/p/eec63026f8d0
上面这篇博客基于C++11新特性用100行代码实现了线程池,代码比较简洁易读,但是没有对任务队列的最大数量进行限制,以及在线程池中线程空闲线程为0时没有相应的处理。
本文主要根据参考博客实现以下功能:
1.管理一定数量的线程,当有任务commit进来的时候,唤醒池中的线程处理任务。
2.当线程池中空闲线程为0时,等待其他线程处理完毕,再进行线程唤醒
3.对任务队列最大数量进行限制,当任务队列满时,阻塞commit函数调用的线程
具体代码如下,代码中基本每一行都加了注释:
#include <vector>
#include <queue>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <QDebug>
#include <iostream>
#include <omp.h>
class threadpool
{
private:
using Task = std::function<void()>; //using 相当于typedef
std::vector<std::thread> m_threads;
std::queue<Task> m_tasks; //任务队列
std::mutex m_lock;
std::condition_variable m_cvTask; //条件变量
std::atomic<bool> m_stoped; //是否关闭提交 std::atomic<T> 对于对象的操作都是原子的不用加锁
std::atomic<int> m_idlThrNum; //空闲线程数量
//std::atomic<bool> m_stoped;
std::atomic<int> m_taskNum;
std::atomic<int> m_maxTaskNum; //任务队列的最大任务数量
public:
inline threadpool(unsigned short size = 4,int maxTask = 500) :m_stoped(false)
{
m_idlThrNum = size < 1 ? 1 : size; //如果传入的构造线程数量为1以下,那默认为1
m_maxTaskNum= maxTask< 1 ? 1 : maxTask;
m_taskNum.store(0);
for (size = 0; size < m_idlThrNum; ++size)
{
m_threads.emplace_back([this]{
while(!this->m_stoped)//如果关闭为假,执行循环
{
Task task;
{
std::unique_lock<std::mutex> lock(this->m_lock);
this->m_cvTask.wait(lock,[this]{
//当停止为真或者任务队列不为空时信号量触发,取消阻塞状态
return this->m_stoped.load() || !this->m_tasks.empty();
});
//当信号量触发前一直阻塞在这里
if(this->m_stoped && this->m_tasks.empty())
return;//当触发线程池停止时,任务队列也为空,就结束线程
task = std::move(this->m_tasks.front()); // 取一个 task
this->m_tasks.pop(

最低0.47元/天 解锁文章
247





