c++线程池

main.cpp

#include<iostream>
#include<chrono>
#include"threadpool.h"


//尽量在c++14以上环境运行
//尽量在c++14以上环境运行
//尽量在c++14以上环境运行
//尽量在c++14以上环境运行
//尽量在c++14以上环境运行
/*必看*/
/*必看*/
//使用时需要构造一个类
// 在main.cpp中的MyTask类
// 将里面的Any tun()函数进行重载,返回值可以是任意类
// Result res1 = pool.submitTask(std::make_shared<MyTask>(1, 1000));
// int sum1 = res1.getRes().cast_<int>();
// 提取结果是要把cast_<int>里的int类型改为你自己所需要的数据类型
// 线程池有两种模式,一种是Cached,另一种是Fixed
// 析构线程池时,会在50s后析构线程池,如需修改这个时间只要在threadpool.cpp里面修改WAIT_TIME即可
//如对代码有任何疑问,请在博客留言或者发私信

class MyTask : public Task
{
public:
MyTask(int begin, int end)
        : begin_(begin)
        , end_(end)
    {}
    // 问题一:怎么设计run函数的返回值,可以表示任意的类型
    Any run()  // run方法最终就在线程池分配的线程中去做执行了!
    {
        std::cout << "tid:" << std::this_thread::get_id()
            << "begin!" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(2));
        int sum = 0;
        for (int i = begin_; i <= end_; i++)
            sum += i;
        std::cout << "tid:" << std::this_thread::get_id()
            << "end!" << std::endl;
        return sum;
    }
private:
    int begin_;
	int end_;
};
int main(void)
{
    {
        ThreadPool pool;
        pool.setMode(PoolMode::MODE_CACHED);
        // 开始启动线程池
        pool.start(2);
        Result res1 = pool.submitTask(std::make_shared<MyTask>(1, 1000));
        Result res2 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));
        Result res3 = pool.submitTask(std::make_shared<MyTask>(1, 1000));
        Result res4 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));
        Result res5 = pool.submitTask(std::make_shared<MyTask>(1, 1000));
        Result res6 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));
        Result res7 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));
        Result res8 = pool.submitTask(std::make_shared<MyTask>(1001, 2000));
        int sum1 = res1.getRes().cast_<int>();
        int sum2 = res2.getRes().cast_<int>();
        int sum3 = res3.getRes().cast_<int>();
        int sum4 = res4.getRes().cast_<int>();
        int sum5 = res5.getRes().cast_<int>();
        int sum6 = res6.getRes().cast_<int>();
        int sum7 = res7.getRes().cast_<int>();
        int sum8 = res8.getRes().cast_<int>();
        std::cout << "结果为结果为" << sum1 << std::endl;
        std::cout << "结果为结果为" << sum2 << std::endl;
        std::cout << "结果为结果为" << sum3 << std::endl;
        std::cout << "结果为结果为" << sum4 << std::endl;
        std::cout << "结果为结果为" << sum5 << std::endl;
        std::cout << "结果为结果为" << sum6 << std::endl;
        std::cout << "结果为结果为" << sum7 << std::endl;
        std::cout << "结果为结果为" << sum8 << std::endl;

        std::cout << "main over!" << std::endl;
		getchar();//把下面的括号移到getchar的上一行就会析构失败,因为所有的线程都在等待条件变量
    }  
    std::cout << "main  over over over!" << std::endl;
    return 0;
}

threadpool.cpp

#include"threadpool.h"
#include<functional>

const int TASK_MAX_THREADHOLD = 1024;
const int WAIT_TIME = 50;

ThreadPool::ThreadPool():m_initThreadSize(0),m_taskSize(0)
						,m_maxTaskSize(TASK_MAX_THREADHOLD)
						,m_poolMode(PoolMode::MODE_FIXED)
						,m_idleThread(0)
						,m_curRunningThread(0)
						,m_threadSize(0)
						,m_maxThread(300)
						,m_isRunning(false)
{}
ThreadPool::~ThreadPool()
{
	std::cout << "线程池析构" << std::endl;
	m_isRunning = false;
	//等待线程池里面的所有线程返回  有两种状态,阻塞&正在执行
	std::unique_lock<std::mutex> lock(m_taskQueMtx);
	std::cout << "获得锁成功" << std::endl;
	m_notEmpty.notify_all();
	m_exit_Cond.wait(lock, [&]()->bool {return m_threads.size() == 0; });
	std::cout << "线程池析构成功" << std::endl;
	
}
void ThreadPool::setMaxThread(int maxThread)
{
	m_maxThread = maxThread;
}
void ThreadPool::setMode(PoolMode mode)
{
	m_poolMode = mode;
}
void ThreadPool::setMaxTaskSize(int maxTaskSize)
{
	m_maxTaskSize = maxTaskSize;
}

Result ThreadPool::submitTask(std::shared_ptr<Task> sp)
/*函数作用:用于把任务提交给任务队列*/
{
	/*对于线程池,必定有任务提交失败的可能*/
	//获取锁
	std::unique_lock<std::mutex> lock(m_taskQueMtx);
	//线程间通信  等待任务队列有空余   
// 
	// wait(一直等待)  wait_for(等待一段时间)  wait_untill(直到某件事情)
	//用户提交任务,最长阻塞不能超过1s,否则任务提交失败,返回

	if (!m_notFull.wait_for(lock, std::chrono::seconds(1), [&]()->bool {return m_taskQue.size() < (size_t)m_maxTaskSize; }))
	{
		std::cerr << "任务未进入线程" << std::endl;
		return Result(sp, false);
	}
	//如果有空余,把空余放入任务队列中
	m_taskQue.emplace(sp);
	m_taskSize++;
	//因为新放了任务,任务队列肯定不空了,notEmpty通知
	m_notEmpty.notify_all();
	if (m_poolMode == PoolMode::MODE_CACHED
		&& m_taskSize > m_initThreadSize
		&& m_threadSize < m_maxTaskSize)
	{
		std::cout << ">>> create new thread..." << std::endl;
		//创建线程对象
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this,std::placeholders::_1));
		int threadID = ptr->getID();
		m_threads.emplace(threadID,std::move(ptr));
		m_threads[threadID]->start(); //如果把这行删除,新的线程将只创建不启动,会导致线程池的动态性受到影响
		m_threadSize++;
		m_idleThread++;
	}
	return Result(sp);
}
void ThreadPool::start(int initTaskSize)
{
	m_isRunning = true;
	m_initThreadSize = initTaskSize;
	m_threadSize = initTaskSize;
	//创建线程对象
	for (int i = 0; i < initTaskSize; i++)
	{
		//创建thread线程对象时,把线程函数给到thread线程对象
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this,std::placeholders::_1));
		int threadID = ptr->getID();
		m_threads.emplace(threadID,std::move(ptr));
	}
	//启动所有线程
	for (int i = 0; i < initTaskSize; i++)
	{
		m_threads[i]->start();
		m_idleThread++;
	}
}

void ThreadPool::threadFunc(int threadID)//线程函数返回,线程结束
{
	auto lastTime = std::chrono::high_resolution_clock().now();	
	for (;;)
	{
		std::shared_ptr<Task> task;
		{
			//先获取锁
			std::unique_lock<std::mutex> lock(m_taskQueMtx);
			while (m_taskQue.size() == 0)
			{
			if (!m_isRunning)
			{
				m_threads.erase(threadID); // std::this_thread::getid()
				std::cout << "threadid:" << std::this_thread::get_id() << " exit!"
						<< std::endl;
				m_exit_Cond.notify_all();
				return; // 线程函数结束,线程结束
			}
				if (m_poolMode == PoolMode::MODE_CACHED)
				{
					if(std::cv_status::timeout ==
						m_notEmpty.wait_for(lock, std::chrono::seconds(1)))
					{
						auto now = std::chrono::high_resolution_clock().now();
						auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
						if (dur.count() > WAIT_TIME && m_threadSize > m_initThreadSize)
						{
							m_threads.erase(threadID);
							m_threadSize--;
							m_idleThread--;
							std::cout << "threadId: " << std::this_thread::get_id() << " exit"
								<< std::endl;
							return;
						}
					 }
				  }
				else			
				{
					m_notEmpty.wait(lock);
				}
			//线程池要结束,回收线程资源				
			}
			// 从任务队列中取出一个任务来执行
			m_idleThread--;
			task = m_taskQue.front();
			m_taskQue.pop();
			m_taskSize--;
		
			//取出一个任务后应该进行通知
			if (m_taskQue.size() > 0)
			{
				m_notEmpty.notify_all();
			}
			m_notFull.notify_all();
		}//{}用于释放锁
		if (task != nullptr)
		{
			//std::cout << "获取任务成功: " << std::this_thread::get_id() << std::endl;
			task->exec();			
		}	
		//更新线程调度执行完任务的时间
		m_idleThread++;
		lastTime = std::chrono::high_resolution_clock().now();	
	}
}

//线程方法实现
int Thread::m_generateID = 0;
//启动线程
int Thread::getID()const
{
	return m_threadID;
}

void Thread::start()
{
	std::thread t(m_func,m_threadID);
	t.detach();
}

Thread::Thread(ThreadFunc func) :m_func(func), m_threadID(m_generateID++)
{

}

Thread::~Thread()
{

}
/*Result类成员函数*/
Result::Result(std::shared_ptr<Task> task, bool isVaild) :m_isVaild(isVaild), m_task(task)
{
	m_task->setResult(this);
}

Any Result::getRes()
{
	if (!m_isVaild)
	{
		return "";
	}
	m_semaphore.wait();
	//task如果没有执行完,会一直等待
	return std::move(m_any);
}
void Result::setRes(Any any)
{
	//存储task的返回值
	this->m_any = std::move(any);
	m_semaphore.post();
}
/*task成员函数实现*/
Task::Task():m_res(nullptr){}
void Task::exec()
{
	if (m_res != nullptr)
	{
		m_res->setRes(run());
	}	
}

void Task::setResult(Result* res)
{
	m_res = res;
}

threadpool.h

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include<iostream>
#include<vector> // 存放线程的容器
#include<queue>  // 存放任务的队列
#include<memory> //控制用户传进来的对象的生命周期
#include<mutex>
#include<atomic>
#include<condition_variable>//条件变量
#include<thread>
#include<functional>
#include<unordered_map>

class Any;
class Result;
class Task//任务的抽象基类
{
public:
	Task();
	~Task() = default;
	void exec();
	virtual Any run() = 0;
	void setResult(Result* res);
private:
	Result* m_res;
	//不能用强智能指针,强智能指针的交叉问题
	//result的生命周期应该强于Task
};


class Thread
{
public:
	using ThreadFunc = std::function<void(int)>;
	Thread(ThreadFunc func);
	~Thread();
	void start();
	int getID()const;
private:
	ThreadFunc m_func;
	static int m_generateID;
	int m_threadID;//线程ID,方便删除
};

class Any
{
public:
	Any() = default;
	~Any() = default;
	Any(const Any&) = delete;
	Any& operator=(const Any&) = delete;
	Any(Any&&) = default;
	Any& operator=(Any&&) = default;

	//模版构造函数,可以接受任意类型数据,并将其存储在派生类当中
	template<typename T>
	Any(T data) :m_base(std::make_unique<Derive<T>>(data))
	{

	}

	template<typename T>
	T cast_()
	{
		//通过dynamic_cast将基类指针转化为派生类,进而获取数据
		Derive<T>* pd = dynamic_cast<Derive<T>*>(m_base.get());//m_base.get()返回指向base类对象的原始指针
		if (pd == nullptr)
		{
			throw "type is unmatch!";
		}
		return pd->m_data;
	}
private:
	class Base
	{
	public:
		virtual ~Base() = default;
	};
	template<typename T>
	class Derive : public Base
	{
	public:
		Derive(T data) :m_data(data) {}
		T m_data;
	};
private:
	std::unique_ptr<Base> m_base;
};

//实现一个信号量类
//既然是线程通信,那么条件变量和锁是必要的
class Semaphore
{
public:
	Semaphore(int limit = 0) :m_resLimit(limit) {}
	~Semaphore() = default;
	//获取一个信号量资源
	void wait()
	{
		std::unique_lock<std::mutex> lock(m_mtx);
		m_condition.wait(lock, [&]()->bool {return m_resLimit > 0; });
		m_resLimit--;
	}
	//增加一个信号量资源
	void post()
	{
		std::unique_lock<std::mutex> lock(m_mtx);
		m_resLimit++;
		m_condition.notify_all();
	}
private:
	int m_resLimit;
	std::mutex m_mtx;
	std::condition_variable m_condition;
};

class Result
{
public:
	Result(std::shared_ptr<Task>, bool isVaild = true);
	~Result() = default;
	Any getRes();
	void setRes(Any any);
private:
	Any m_any;
	Semaphore m_semaphore;
	std::shared_ptr<Task> m_task;
	std::atomic_bool m_isVaild;
};

//线程池支持的模式
enum class PoolMode
{
	MODE_FIXED,//固定数量的线程
	MODE_CACHED,//线程数量可动态增长
};

//线程类型
class ThreadPool
{
public:
	ThreadPool();
	~ThreadPool();
	void setMode(PoolMode mode);
	void setMaxTaskSize(int maxTaskSize);
	Result submitTask(std::shared_ptr<Task> sp);
	void start(int initTaskSize = 0);
	ThreadPool(const ThreadPool&) = delete;
	ThreadPool& operator=(const ThreadPool&) = delete;
	void setMaxThread(int maxThread);
private:
	void threadFunc(int threadID);
	std::atomic_int m_idleThread;
	int m_curRunningThread;
	int m_maxThread;
	std::atomic_int m_threadSize;//当前线程数量
private:
	//std::vector<std::unique_ptr<Thread>> m_threads;//线程容器
	std::unordered_map<int,std::unique_ptr<Thread>> m_threads;
	int m_initThreadSize;//初始线程数量
	std::queue<std::shared_ptr<Task>> m_taskQue;//任务队列
	int m_taskSize;//任务数量
	int m_maxTaskSize;//最大任务数量
	PoolMode m_poolMode;
	std::atomic_bool m_isRunning;
	std::condition_variable m_exit_Cond;//等待线程资源全部回收

	std::condition_variable m_notFull;//任务队列不为满
	std::condition_variable m_notEmpty;//任务队列不为空
	std::mutex m_taskQueMtx; //线程锁,保证任务队列的线程安全
};
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值