c++ 线程池的实现与使用

主要是自己看的一些,注释和参考都写在代码里了,我总和一下,备忘和记录。

头文件

/*********************************************************************************************
    *  @Copyright (c) , All rights reserved.
    *  @file:       threadpool.h
    *  @version:    ver 1.0
    *  @author:     闹闹
    *  @brief:      线程池代码整和
    *  @change:
    *  @email: 	1319144981@qq.com
    *  Date             Version    Changed By      Changes 
    *  2021/5/10 16:18:20    1.0       闹闹            create
	写一句自己最喜欢的话吧。
	为天地立心,为生民立命,为往圣继绝学,为万世开太平。
**********************************************************************************************/
#pragma once
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__
#include <thread>
#include <mutex>
#include <iostream>
#include <future>
#include <chrono>
#include <queue>
#include <vector>
#include <assert.h>
#include <stddef.h>
#include <condition_variable>
/******************************************************************************
* @FuncName:  
* @Author:    闹闹
* @Brief:    Event是一个同步对象,它允许一条线程通知另外的一条或者多条线程特定的事件已经发生了。
* @Version:   1.0.0.1
* @Date:	  2021/5/10 16:24
* @InputParameter: 
* @OutputParameter: 
* @Returns:   
* @Others:   
参考博客
			https://blog.csdn.net/FlushHip/article/details/82840301
wait的函数解释
			https://zh.cppreference.com/w/cpp/thread/condition_variable/wait
			使用Event特别容易出现死锁,避免把Event的操作放在锁的范围中,
			因为Event本身就有一把锁,锁套锁,一不小心,加锁顺序错乱就死锁了。
用一个标志变量来标识特定的事件是否发生了(条件满足就设置标志变量,把业务逻辑分离出去),
再用一个标志变量标识是否全部唤醒。
******************************************************************************/
class Event{
private:
	Event(const Event &) = delete;													//删除拷贝和赋值构造函数
	Event & operator = (const Event &) = delete;
private:
	bool flag = false;																//一个标识变量标识特定事件是否发生
	bool all = false;																//一个标志变量标识是否全部唤醒
	std::mutex mu;
	std::condition_variable con;
public:
	Event() = default;
	void Wait(){
		std::unique_lock<std::mutex> lock(mu);
		con.wait(lock, [this]() {
			return this->flag || this->all;
		});
		if (!all)
			flag = false;
	}
	template<typename _Rep, typename _Period>
	bool WaitFor(const std::chrono::duration<_Rep, _Period>& duration){
		std::unique_lock<std::mutex> lock(mu);
		bool ret = true;
		ret = con.wait_for(lock, duration, [this]() {
			return this->flag || this->all;
		});
		if (ret && !all)
			flag = false;
		return ret;
	}
	template<typename _Clock, typename _Duration>
	bool WaitUntil(const std::chrono::time_point<_Clock, _Duration>& point){
		std::unique_lock<std::mutex> lock(mu);
		bool ret = true;
		ret = con.wait_until(lock, point, [this]() {
			return this->flag || this->all;
		});
		if (ret && !all)
			flag = false;
		return ret;
	}
	void NotifyOne(){
		std::lock_guard <std::mutex> lock(mu);
		flag = true;
		con.notify_one();
	}
	void NotifyAll(){
		std::lock_guard<std::mutex> lock(mu);
		all = true;
		con.notify_all();
	}
	void Reset(){
		std::lock_guard<std::mutex> lock(mu);
		flag = all = false;
	}
};

/******************************************************************************
* @FuncName:  
* @Author:    闹闹
* @Brief:     brief
* @Version:   1.0.0.1
* @Date:	  2021/5/10 16:35
* @InputParameter: 
* @OutputParameter: 
* @Returns:   
* @Others:  
参考博客
			https://blog.csdn.net/FlushHip/article/details/82852378
可变参数模板
			https://www.cnblogs.com/qicosmos/p/4325949.html
C++中可以把变量和锁绑定在一起作为一个对象,
使得这个对象平时使用起来和变量无异,只不过这个对象带了一把锁。
******************************************************************************/
#define MUTEXOBJECT_LOCK_GUARD(obj) std::lock_guard<std::mutex> lock(obj.Mutex())
#define MUTEXOBJECT_UNIQUE_LOCK(obj) std::unique_lock<std::mutex> lock(obj.Mutex())

template<typename T>
class MutexObject{
private:
	T data;
	std::mutex mu;
public:
	MutexObject() {}
	//可变参数模板
	template<typename... Args>
	MutexObject(Args... args) :data(args...) {}
	MutexObject<T>& operator =(const T &data){
		this->data = data;
		return *this;
	}
	MutexObject<T>& operator = (const MutexObject<T> &other){
		this->data = other.data;
		return *this;
	}
	operator T &() { return data; }
	operator T && () { return std::move(data); }
	T * operator -> () { return &data; }
	T * operator & () { return operator->(); }
	std::mutex & Mutex() { return mu; }
	T & Data() { return data; }
};

/******************************************************************************
* @FuncName:  
* @Author:    闹闹
* @Brief:     线程池
* @Version:   1.0.0.1
* @Date:	  2021/5/10 16:38
* @InputParameter: 
* @OutputParameter: 
* @Returns:   
* @Others:  
参考链接
https://blog.csdn.net/FlushHip/article/details/82882301#comments_13516343
https://blog.csdn.net/windpenguin/article/details/75581552
https://blog.csdn.net/u011726005/article/details/78266706
获取线程返回结果
fu= pool.Submit(fun, i);
fu.get();
阻塞等待返回
fu.wait()
******************************************************************************/
class ThreadPool{
	typedef std::function<void()> Task;
	typedef std::queue<Task>  TaskQueue;
	typedef std::shared_ptr<std::thread> ThreadPtr;
	typedef std::vector<ThreadPtr> Pool;

private:
	MutexObject<Pool> pool;
	MutexObject<TaskQueue> taskQueue;
	Event event;
	size_t coreCnt;
	bool expand;
	size_t maxCnt;
	std::atomic<bool> run;
public:
	ThreadPool(size_t coreCnt = 1, bool expand = false, size_t maxCnt = std::thread::hardware_concurrency())
		:coreCnt(coreCnt)
		, expand(coreCnt ? expand : true)
		, maxCnt(maxCnt)
		, run(true)
	{}

	~ThreadPool(){
		Close();
	}

	void Start(){
		run = true;
		event.Reset();
	}

	void Close(){
		run = false;
		event.NotifyAll();
		Pool vec;
		do 
		{
			MUTEXOBJECT_LOCK_GUARD(pool);
			vec = pool.Data();
		} while (false);

		std::for_each(std::begin(vec), std::end(vec), [](const ThreadPtr& it) {
			if (it->joinable())
			{
				if (std::this_thread::get_id() == it->get_id())
				{
					it->detach();
				}
				else
				{
					it->join();
				}
			}
		});
	}

	template<typename Fun,typename...Args>
	std::future<typename std::result_of<Fun(Args...)>::type> Submit(Fun && fun, Args&&... args){
		if (!run.load())
			throw std::runtime_error("ThreadPool has closed");
		typedef typename std::result_of<Fun(Args...)>::type ReturnType;
		auto task = std::make_shared<std::packaged_task<ReturnType()>>
			(std::bind(std::forward<Fun>(fun), std::forward<Args>(args)...));
		do 
		{
			MUTEXOBJECT_LOCK_GUARD(taskQueue);
			taskQueue->emplace([task]() 
			{
				(*task)();
			});
			//std::cout << "任务队列加入任务" << std::endl;
		} while (false);
		event.NotifyOne();
		if (NeedNewThread())
		{
			NewThread();
		}
		return task->get_future();
	}
private:
	bool NeedNewThread(){
		do 
		{
			MUTEXOBJECT_LOCK_GUARD(pool);
			if (pool->empty())
				return true;
			if (pool->size() == maxCnt)
				return false;
		} while (false);
		do 
		{
			MUTEXOBJECT_LOCK_GUARD(taskQueue);
			return taskQueue->size() > 0;
		} while (false);
		
		assert(false);
	}

	void NewThread(){
		MUTEXOBJECT_LOCK_GUARD(pool);
		if (pool->size() < coreCnt)
		{
			pool->emplace_back(new std::thread(std::bind(&ThreadPool::Dispath,this,true)));
		}
		else if (expand)
		{
			pool->emplace_back(new std::thread(std::bind(&ThreadPool::Dispath,this,false)));
		}
	}

	void Dispath(bool core){
		while (run.load())
		{
			if (Task task = PickOneTask())
			{
				task();
			}
			else if (!event.WaitFor(std::chrono::minutes(1)) && !core)
			{
				KillSelf();
				break;
			}
		}
	}

	void KillSelf(){
		MUTEXOBJECT_LOCK_GUARD(pool);
		auto it = std::find_if(std::begin(pool.Data()), std::end(pool.Data()), [](const ThreadPtr &it) 
		{
			return std::this_thread::get_id() == it->get_id();
		});
		(*it)->detach();
		pool->erase(it);
	}

	Task PickOneTask(){
		MUTEXOBJECT_LOCK_GUARD(taskQueue);
		Task ret = nullptr;
		if (!taskQueue->empty()) {
			ret = std::move(taskQueue->front());
			taskQueue->pop();
			//std::cout << "任务队列弹出任务" << std::endl;
		}
		return ret;
	}
};
#endif  //__THREADPOOL_H__
int example()
{
	auto th = std::thread(consume);
	std::this_thread::sleep_for(std::chrono::seconds(2));
	std::thread(produce).join();
	th.join();
	system("pause");
	return 0;
}

example_2.cpp

#include "threadpool.h"

#include <iostream>


std::mutex g_mu;
int fun(int n)
{
	{
		//线程同步需要自己做
		std::unique_lock<std::mutex> lock(g_mu);
		std::cout << "Fun输出 n : " << n << std::endl;
		return n;
	}
	
	//std::this_thread::sleep_for(std::chrono::milliseconds(500));
}

void work()
{
	static const int LEN = 30;
	ThreadPool pool(4, true, 10);
	int n = 5;
	pool.Submit(fun, n);
	
	{
		std::unique_lock<std::mutex> lock(g_mu);
		std::cout << "n : " << n << std::endl;
	}
	std::this_thread::sleep_for(std::chrono::seconds(2));
	pool.Submit(fun, 1);
	pool.Close();
	

	std::cout << "********************** " << std::endl;
	pool.Start();
	std::future<int> fu[LEN];
	for (int i = 0; i < LEN; i++)
		fu[i] = pool.Submit(fun, i);
	/*
	wait 是阻塞线程,等待线程结束
	*/
	for (int i = 0; i < LEN; fu[i++].wait()) {}
	std::cout << "获取结果******* " << std::endl;
	for (int i = 0; i < LEN;i++)
	{
		//get取得线程返回值
		int value = fu[i].get();
		std::cout << "第"<<i<<"个线程结果:"<< value << std::endl;

	}
	pool.Close();
}

int main()
{
	work();
	std::this_thread::sleep_for(std::chrono::seconds(2));

	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值