C++ 实现线程池 --- Linux+Windows环境通用

大家好,我是 DongGu ,是一名软件工程专业大二的学生,写博客一方面是为了记录自己的学习过程,把自己犯的错误进行分享。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!有任何问题可以评论 或者 ___>
QQ联系(1521839703)

  • 本代码还是跟老王学到的, 只不过那个是linux版本,改成c++11可以在win下进行调试,
  • 对于一些函数本质原理不太了解,

为什么要用到线程池:

1. 肯定是为了速度,并且提前创建好线程, 避免动态创建线程,提高了稳定性
2. 用类来管理和调度这些线程, 不断循环, 调度,处理, 显著的提高运行效率


#include<vector>
#include<atomic>
#include<mutex>
#include<list>
#include<thread>
#include<iostream>
#include<Windows.h>
#include<algorithm>
#include<condition_variable>

using namespace std;


class CThreadPool {
public:

	struct ThreadItem
	{
		thread					mythread;
		CThreadPool*			_pThis;                        //记录线程池的指针	
		bool					ifrunning;                      //标记是否正式启动起来,启动起来后,才允许调用StopAll()来释放

		//构造函数
		ThreadItem(CThreadPool* pthis) :_pThis(pthis), ifrunning(false) {}
		//析构函数
		~ThreadItem() {}
	};

	CThreadPool();
	~CThreadPool();

	void* ThreadFunc(void* threadData);      //新线程的线程回调函数    
	bool Create(int threadNum);                     //创建该线程池中的所有线程
	void StopAll();                                 //使线程池中的所有线程退出
	void clearMsgRecvQueue();                       //清理接收消息队列
	void inMsgRecvQueueAndSignal(char* buf);        //收到一个完整消息后,入消息队列,并触发线程池中线程来处理该消息
	void Call();                                    //来任务了,调一个线程池中的线程下来干活  
	int  getRecvMsgQueueCount() { return m_iRecvMsgQueueCount; } //获取接收消息队列大小

	static bool					m_shutdown;          //线程退出标志,false不退出,true退出

	int							m_iThreadNum;        //要创建的线程数量

	std::atomic<int>			m_iRunningThreadNum; //线程数, 运行中的线程数,原子操作

	std::vector<ThreadItem*>	m_threadVector;      //线程 容器,容器里就是各个线程了 

	//接收消息队列相关
	list<char*>					m_MsgRecvQueue;      //接收数据消息队列 
	int							m_iRecvMsgQueueCount;//收消息队列大小


	mutex m_pthreadMutex;
	condition_variable m_pthreadCond;
};

bool CThreadPool::m_shutdown = false;          //线程退出标志,false不退出,true退出

//构造函数
CThreadPool::CThreadPool()
{
	m_iRunningThreadNum = 0;  //正在运行的线程,开始给个0【注意这种写法:原子的对象给0也可以直接赋值,当整型变量来用】
	m_iRecvMsgQueueCount = 0; //收消息队列
}

//析构函数
CThreadPool::~CThreadPool()
{
	//资源释放在StopAll()里统一进行,就不在这里进行了
	//接收消息队列中内容释放
	clearMsgRecvQueue();
}

void CThreadPool::clearMsgRecvQueue()
{
	char* sTmpMempoint;

	//尾声阶段,需要互斥?该退的都退出了,该停止的都停止了,应该不需要退出了
	while (!m_MsgRecvQueue.empty())
	{
		sTmpMempoint = m_MsgRecvQueue.front();
		cout << "delete -> " << sTmpMempoint << endl;
		m_MsgRecvQueue.pop_front();
		delete[]sTmpMempoint;
	}
}

bool CThreadPool::Create(int threadNum) 
{
	ThreadItem* pNew;
	m_iThreadNum = threadNum; //保存要创建的线程数量    
	for (int i = 0; i < m_iThreadNum; ++i)
	{
		m_threadVector.push_back(pNew = new ThreadItem(this));             //创建 一个新线程对象 并入到容器中         

		pNew->mythread = thread(&CThreadPool::ThreadFunc, this, pNew);
	} //end for

	std::vector<ThreadItem*>::iterator iter;
lblfor:
	for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
	{
		cout << (*iter)->mythread.get_id() << "'s ifrunning " << (*iter)->ifrunning << endl;
		if ((*iter)->ifrunning == false) //这个条件保证所有线程完全启动起来,以保证整个线程池中的线程正常工作;
		{
			Sleep(100);  //100毫秒
			goto lblfor;
		}
	}
	return true;
}

void* CThreadPool::ThreadFunc(void* threadData)      //新线程的线程回调函数    
{
	ThreadItem* pThread = static_cast<ThreadItem*>(threadData);
	CThreadPool* pThreadPoolObj = pThread->_pThis;

	while (1) {
		
		/*
		* 疑问, 是不是每个锁到这里,都是创建一个没有加锁的unique,有待测试,主要condition_variable要unique类型
		*/
		unique_lock<mutex> lck(m_pthreadMutex);//创建一个没有加锁的myunique_lock

		while ((pThreadPoolObj->m_MsgRecvQueue.size() == 0) && m_shutdown == false)
		{
			if (pThread->ifrunning == false)
			{
				pThread->ifrunning = true;
				cout << pThread->mythread.get_id() << "ifrunning ok \n ";
			}

			m_pthreadCond.wait(lck);
		}

		if (m_shutdown)
		{
			cout << pThread->mythread.get_id() << "'shutdown " << endl;
			lck.unlock();
			break;
		}

		//走到这里,可以取得消息进行处理了【消息队列中必然有消息】,注意,目前还是互斥着呢
		char* jobbuf = pThreadPoolObj->m_MsgRecvQueue.front();     //返回第一个元素但不检查元素存在与否
		pThreadPoolObj->m_MsgRecvQueue.pop_front();                //移除第一个元素但不返回	
		--pThreadPoolObj->m_iRecvMsgQueueCount;                    //收消息队列数字-1

		//可以解锁互斥量了
		lck.unlock();
		//能走到这里的,就是有消息可以处理,开始处理
		++pThreadPoolObj->m_iRunningThreadNum;    //原子+1【记录正在干活的线程数量增加1】,这比互斥量要快很多

		cout << "\t\t" << pThread->mythread.get_id() << "get : " << jobbuf << endl;


		delete[]jobbuf;
		--pThreadPoolObj->m_iRunningThreadNum;     //原子-1【记录正在干活的线程数量减少1】
	}
	return (void*)0;
}

void CThreadPool::StopAll()                                 //使线程池中的所有线程退出
{
	//(1)已经调用过,就不要重复调用了
	if (m_shutdown == true)
	{
		return;
	}
	m_shutdown = true;

	//(2)唤醒等待该条件【卡在pthread_cond_wait()的】的所有线程,一定要在改变条件状态以后再给线程发信号
	m_pthreadCond.notify_all();

	//(3)等等线程,让线程真返回    
	std::vector<ThreadItem*>::iterator iter;
	for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
	{
		(*iter)->mythread.join();
	}


	//(4)释放一下new出来的ThreadItem【线程池中的线程】    
	for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
	{
		if (*iter)
			delete* iter;
	}
	m_threadVector.clear();

	printf("CThreadPool::StopAll()成功返回,线程池中线程全部正常结束!\n");
	return;
}

void CThreadPool::inMsgRecvQueueAndSignal(char* buf)        //收到一个完整消息后,入消息队列,并触发线程池中线程来处理该消息
{
	unique_lock<mutex> lck(m_pthreadMutex);
	m_MsgRecvQueue.push_back(buf);
	++m_iRecvMsgQueueCount;

	lck.unlock();
	Call();
	return;
}

void CThreadPool::Call()                                   //来任务了,调一个线程池中的线程下来干活  
{
	m_pthreadCond.notify_one();
}

int main()
{
	// 检测是否有内存泄漏
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	CThreadPool* pCThreadPool = new CThreadPool();
	pCThreadPool->Create(10);


	for (int i = 0; i < 1000; ++i) 
	{
		char* mess = new char[10];
		sprintf(mess, "hello %d", i);
		pCThreadPool->inMsgRecvQueueAndSignal(mess);
	}

	Sleep(10000);
	// 防止m_shutdown提前 为true, 只是测试用 
	pCThreadPool->StopAll();

	cout << sizeof(CThreadPool) << endl;

	delete pCThreadPool;

	return 0;
}
  • my
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<cstring>
#include<algorithm>
#include<string>
#include<Windows.h>

using namespace std;


class CThreadPool {

public:
	class CThreadItem {
	public:
		bool					is_running;
		thread					mythread;
		CThreadPool				*p_This;
		//构造函数
		CThreadItem(CThreadPool* pthis) :p_This(pthis), is_running(false) {
			cout << this << endl;
		}
		//析构函数
		~CThreadItem() {}
	};

	static bool					m_shutdown;          //线程退出标志,false不退出,true退出
	int m_iThreadNum;

	CThreadPool();
	~CThreadPool();
	void Stopall();
	void Call();
	void Creat(int);
	void *ThreadFun(void *);

	void inMsgRecvQueueAndSignal(char*);

	vector<char*>				m_msg;
	vector<CThreadItem*>		m_threadVec;

	mutex						m_pthreadMutex;
	condition_variable			m_pthreadCond;
};	

bool CThreadPool::m_shutdown = false;

CThreadPool::CThreadPool() {

}
CThreadPool::~CThreadPool() {
lblfor1:
	for (auto iter = m_msg.begin(); iter != m_msg.end(); ++iter) {
		char* buf = *iter;
		delete[]buf;
		goto lblfor1;
	}
}
void CThreadPool::Call() {
	m_pthreadCond.notify_one();
}
void CThreadPool::Stopall() {
	if (m_shutdown) {
		return ;
	}

	m_shutdown = true;
	m_pthreadCond.notify_all();

	for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); iter++)
	{
		(*iter)->mythread.join();
	}
	
	cout << "------\n";
	
	for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); iter++)
	{
		CThreadItem* tmp = *iter;
		cout << tmp << endl;
		delete tmp;
	}
	cout << "------\n";

	m_threadVec.clear();
	printf("cthreadpool::stopall()成功返回,线程池中线程全部正常结束!\n");
	return;
}
void CThreadPool::Creat(int num) 
{
	m_iThreadNum = num;
	CThreadItem* pNew;

	cout << "------\n";

	for (int i = 0; i < m_iThreadNum; ++i)
	{
		pNew = new CThreadItem(this);
		pNew->mythread = thread(&CThreadPool::ThreadFun, this, pNew);
		m_threadVec.push_back(pNew);
	}
	cout << "------\n";


lblfor:
	for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); ++iter)
	{
		if (!((*iter)->is_running))
		{
			goto lblfor;
		}
	}

	cout << " Creat ok\n";
}
void *CThreadPool::ThreadFun(void *Data) 
{

	CThreadItem* pThread = static_cast<CThreadItem*>(Data);
	CThreadPool* pool = pThread->p_This;

	while (1)
	{
		unique_lock<mutex> lck(m_pthreadMutex);
		while (m_msg.size() == 0 && m_shutdown == false) 
		{
			if (!pThread->is_running) {
				pThread->is_running = true;
			}
			m_pthreadCond.wait(lck);
		}

		if (m_shutdown)
		{
			lck.unlock();
			return (void*)0;
		}


		char* jobbuf = m_msg.front();
		m_msg.erase(m_msg.begin());
		cout << "\t\t\tget:" << jobbuf << endl;
		delete []jobbuf;
		lck.unlock();
	}

	return (void*)0; 
}

void CThreadPool::inMsgRecvQueueAndSignal(char* rhs)
{
	m_pthreadMutex.lock();
	m_msg.push_back(rhs);
	m_pthreadMutex.unlock();
	Call();
}

int main() 
{
	// 检测是否有内存泄漏
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	CThreadPool* pCThreadPool = new CThreadPool();
	pCThreadPool->Creat(10);


	for (int i = 0; i < 1000; ++i)
	{
		char* mess = new char[10];
		sprintf(mess, "hello %d", i);
		pCThreadPool->inMsgRecvQueueAndSignal(mess);
	}

	Sleep(5000);
	pCThreadPool->Stopall();

	cout << sizeof(CThreadPool) << endl;

	delete pCThreadPool;

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DongGu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值