Windows C++ 线程池

        Windows 平台C++ 没什么比较好的官方的线程池,boost里倒是有很方便的线程池,可是为了一个线程池,使用庞大的boost显然不太合适,为此,我在网上找了个demo,然后用C++模板做了些改造,基本上实现了类似boost的threadpool的功能。

首先需要解释的是,以何种方式将线程函数加入队列(我这里用的队列是CList),可以利用类模板和函数模板以及函数指针创建包含该函数的对象,执行时,只需要调用对象中的函数指针即可,这里说明下,因为函数模板在实例化之前是没有任何函数的,因此,自然就不存在指向函数模板的指针。但是可以以另一种方式创建函数模板的指针,即引入类模板。因为类模板实例化之后,其中的函数模板就有意义了。但是,这也出现了个问题,就是类模板中的函数模板无法作为函数指针在类外调用,例如在该头文件对应的cpp文件中调用。因此,不得已需要直接在头文件中定义函数体。

#pragma once

#include "Task.h"
#include <typeinfo>
class ParamTem
{
protected:
	ParamTem(){};
};


template <class ReturnType,class P0=ParamTem,class P1=ParamTem,
class P2=ParamTem,class P3=ParamTem, class P4=ParamTem,
class P5=ParamTem,class P6=ParamTem, class P7=ParamTem>
class CMyTask: public CTask,public ParamTem
{
private:
	typedef ReturnType (*FuncTem)();
	typedef ReturnType (*FuncTem0)(P0 p0);
	typedef ReturnType (*FuncTem1)(P0 p0, P1 p1);
	typedef ReturnType (*FuncTem2)(P0 p0, P1 p1, P2 p2);
	typedef ReturnType (*FuncTem3)(P0 p0, P1 p1, P2 p2,P3 p3);
	typedef ReturnType (*FuncTem4)(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4);
	typedef ReturnType (*FuncTem5)(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5);
	typedef ReturnType (*FuncTem6)(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6);
	typedef ReturnType (*FuncTem7)(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6, P7 p7);
	FuncTem ft;
	FuncTem0 ft0;
	FuncTem1 ft1;
	FuncTem2 ft2;
	FuncTem3 ft3;
	FuncTem4 ft4;
	FuncTem5 ft5;
	FuncTem6 ft6;
	FuncTem7 ft7;
	P0 p0;
	P1 p1;
	P2 p2;
	P3 p3;
	P4 p4;
	P5 p5;
	P6 p6;
	P7 p7;
public:
	CMyTask(FuncTem ft)
	{
		this->ft = ft;
	}
	CMyTask(FuncTem0 ft,P0 p0)
	{
		this->ft0 = ft;
		this->p0 = p0;
	}
	CMyTask(FuncTem1 ft,P0 p0, P1 p1)
	{
		this->ft1 = ft;
		this->p0 = p0;
		this->p1 = p1;
	}
	CMyTask(FuncTem2 ft,P0 p0, P1 p1, P2 p2)
	{
		this->ft2 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
	}
	CMyTask(FuncTem3 ft,P0 p0, P1 p1, P2 p2, P3 p3)
	{
		this->ft3 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
		this->p3 = p3;
	}
	CMyTask(FuncTem4 ft,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4)
	{
		this->ft4 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
		this->p3 = p3;
		this->p4 = p4;
	}
	CMyTask(FuncTem5 ft,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5)
	{
		this->ft5 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
		this->p3 = p3;
		this->p4 = p4;
		this->p5 = p5;
	}
	CMyTask(FuncTem6 ft,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6)
	{
		this->ft6 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
		this->p3 = p3;
		this->p4 = p4;
		this->p5 = p5;
		this->p6 = p6;
	}
	CMyTask(FuncTem7 ft,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6, P7 p7)
	{
		this->ft7 = ft;
		this->p0 = p0;
		this->p1 = p1;
		this->p2 = p2;
		this->p3 = p3;
		this->p4 = p4;
		this->p5 = p5;
		this->p6 = p6;
		this->p7 = p7;
	}
	virtual void Run()
	{
		if(!strcmp(typeid(P0).name(),"class ParamTem"))
		{
			this->ft();
		}
		else if(!strcmp(typeid(P1).name(),"class ParamTem"))
		{
			this->ft0(this->p0);
		}
		else if(!strcmp(typeid(P2).name(),"class ParamTem"))
		{
			this->ft1(this->p0,this->p1);
		}
		else if(!strcmp(typeid(P3).name(),"class ParamTem"))
		{
			this->ft2(this->p0,this->p1,this->p2);
		}
		else if(!strcmp(typeid(P4).name(),"class ParamTem"))
		{
			this->ft3(this->p0,this->p1,this->p2,this->p3);
		}
		else if(!strcmp(typeid(P5).name(),"class ParamTem"))
		{
			this->ft4(this->p0,this->p1,this->p2,this->p3,this->p4);
		}
		else if(!strcmp(typeid(P6).name(),"class ParamTem"))
		{
			this->ft5(this->p0,this->p1,this->p2,this->p3,this->p4,this->p5);
		}
		else if(!strcmp(typeid(P7).name(),"class ParamTem"))
		{
			this->ft6(this->p0,this->p1,this->p2,this->p3,this->p4,this->p5\
				,this->p6);
		}
		else if(strcmp(typeid(P7).name(),"class ParamTem"))
		{
			this->ft7(this->p0,this->p1,this->p2,this->p3,this->p4,this->p5\
				,this->p6,this->p7);
		}
	}
};
如上只定义了到含8个参数的函数模板,如果你们需要执行的函数的参数可能更多,只需要依葫芦画瓢,添加相应的函数模板即可。

另外定义这个类模板是因为在将函数加入队列貌似不太好办,我也不确定办不了,但是我是没搞出来,所以需要借助对象来保存函数。
这里说明两个地方,首先为什么要定义一个父类,而且,父类的构造函数是protected权限的,这个为了避免其他地方调用这个类生成对象,因为它是MyTask的默认模板参数,默认模板参数则是为了避免参数较少时依然要填满所以的模板参数声明。


#include "StdAfx.h"
#include "MyThreadPool.h"

CMyThreadPool::CMyThreadPool(int nThreadCount/* =5 */)
{
	this->m_nThreadCount=nThreadCount; 
	m_bthreadflag = TRUE;
	m_hsemaphore = CreateSemaphore(NULL, 0, 5000, NULL);
	InitializeCriticalSection(&m_csThreadQueue);
	InitializeCriticalSection(&m_csTaskQueue);
	m_pThreadItemList=new std::list<ThreadItem*>;
	m_pTaskList=new std::list<CTask*>;
	EnterCriticalSection(&m_csThreadQueue);
	for (int i=0;i<m_nThreadCount;i++)
	{
		ThreadItem* pItem=new ThreadItem();
		if (pItem)
		{
			pItem->pThreadPool=this;
			pItem->bThreadFlag=TRUE;
			pItem->hThreadHandle= (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)pItem, 0, &pItem->dwThreadID);
			printf("创建线程 threadid:%d\n",pItem->dwThreadID);
			m_pThreadItemList->push_back(pItem);
		}
	}
	LeaveCriticalSection(&m_csThreadQueue);
}

UINT WINAPI CMyThreadPool::ThreadFunc(LPVOID lpParameter /* = NULL */)
{
	//CMyThreadPool* pmyThreadPool = (CMyThreadPool*) lpParameter;
	ThreadItem *pItem = (ThreadItem*) lpParameter;
	CTask * m_pTask = NULL;
	while(pItem->bThreadFlag)
	{
		WaitForSingleObject(pItem->pThreadPool->m_hsemaphore, INFINITE);
		EnterCriticalSection(&pItem->pThreadPool->m_csTaskQueue);
		m_pTask = pItem->pThreadPool->m_pTaskList->front();
		if(m_pTask)
		{
			pItem->pThreadPool->m_pTaskList->pop_front();
		}
		LeaveCriticalSection(&pItem->pThreadPool->m_csTaskQueue);
		m_pTask->Run();
		delete m_pTask;
	}
	return NULL;
}

void CMyThreadPool::StopAllThread()
{
	EnterCriticalSection(&m_csThreadQueue);
	while (!m_pThreadItemList->empty())
	{		
		ThreadItem* pThreadItem=m_pThreadItemList->front();
		if (pThreadItem)
		{
			//TRACE("结束线程 %d\n",pThreadItem->dwThreadID);
			printf("结束线程 %d\n",pThreadItem->dwThreadID);
			pThreadItem->bThreadFlag=FALSE;
			WaitForSingleObject(pThreadItem->hThreadHandle,INFINITE);
			m_pThreadItemList->pop_front();
			delete(pThreadItem);			
		}		
	}
	LeaveCriticalSection(&m_csThreadQueue);
}


void CMyThreadPool::schedule(CTask* pTask)
{	
	EnterCriticalSection(&m_csTaskQueue);
	if (m_pTaskList)
	{
		m_pTaskList->push_back(pTask);
	}
	ReleaseSemaphore(this->m_hsemaphore,1,NULL);
	LeaveCriticalSection(&m_csTaskQueue);
}

CMyThreadPool::~CMyThreadPool()
{
	StopAllThread();
	DeleteCriticalSection(&m_csThreadQueue);
	DeleteCriticalSection(&m_csTaskQueue);
	delete m_pTaskList;
	delete m_pThreadItemList;
}
这是线程池源码,当然正如我在上面所说道的函数模板的问题,在此,其定义的另一个schedule函数需要在头文件中直接定义。
#pragma once
#include "MyTask.h"
#include <list>
#include <process.h>
class CMyThreadPool;
struct ThreadItem
{
	HANDLE hThreadHandle;       //线程句柄
	UINT  dwThreadID;          //线程ID
	BOOL   bThreadFlag;         //线程运行标识
	CMyThreadPool* pThreadPool;   //属于哪个线程池
	ThreadItem()
	{
		hThreadHandle=NULL;
		dwThreadID=0;
		bThreadFlag=FALSE;
		pThreadPool=NULL;
	}
};

class CMyThreadPool
{
public:
	//CMyThreadPool();
	CMyThreadPool(int nThreadCount=5);
	virtual ~CMyThreadPool();
	static UINT WINAPI ThreadFunc(LPVOID lpParameter = NULL);
public:
	void schedule(CTask* pTask);
	std::list<ThreadItem*>* GetThreadItemList() {return m_pThreadItemList;};
	std::list<CTask*>*      GetTaskList() {return m_pTaskList;};
	void               StopAllThread();
	void               AdjustSize(int nThreadCount);  //动态调整线程池规模
protected:
	//static 
private:
	BOOL m_bthreadflag;   
	int m_nThreadCount;    //线程池中线程的个数
	HANDLE m_hsemaphore;
	std::list<ThreadItem*>*  m_pThreadItemList;
	std::list<CTask*>*       m_pTaskList;
	CRITICAL_SECTION    m_csThreadQueue;
	CRITICAL_SECTION    m_csTaskQueue;

	//Schedule 函数定义

public:
	template<typename ReturnType>
	void schedule(ReturnType Func())
	{
		CTask * pTask = new CMyTask<ReturnType>(Func);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
public:
	template <typename ReturnType, typename P0>
	void schedule(ReturnType Func(P0 p0),P0 p0)
	{
		CTask * pTask = new CMyTask<ReturnType,P0>(Func, p0);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1>
	void schedule(ReturnType Func(P0 p0, P1 p1),P0 p0, P1 p1)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1>(Func, p0, p1);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2),P0 p0, P1 p1, P2 p2)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2>(Func, p0, p1, p2);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2, typename P3>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2, P3 p3),P0 p0, P1 p1, P2 p2, P3 p3)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2,P3>(Func, p0, p1, p2, p3);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2, typename P3\
	,typename P4>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4)\
	,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2,P3,P4>(Func, p0, p1, p2, p3, p4);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2, typename P3\
		,typename P4, typename P5>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5)\
	,P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2,P3,P4,P5>(Func, p0, p1, p2, p3, p4, p5);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2, typename P3\
	,typename P4, typename P5, typename P6>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6),\
	P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2,P3,P4,P5,P6>(Func, p0, p1, p2, p3, p4, p5, p6);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
	template <typename ReturnType, typename P0, typename P1,typename P2, typename P3\
	,typename P4, typename P5, typename P6,typename P7>
	void schedule(ReturnType Func(P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6, P7 p7),\
	P0 p0, P1 p1, P2 p2, P3 p3,P4 p4, P5 p5, P6 p6, P7 p7)
	{
		CTask * pTask = new CMyTask<ReturnType,P0,P1,P2,P3,P4,P5,P6,P7>(Func, p0, p1, p2, p3, p4, p5, p6,p7);
		EnterCriticalSection(&m_csTaskQueue);
		if (m_pTaskList)
		{
			m_pTaskList->push_back(pTask);
		}
		ReleaseSemaphore(this->m_hsemaphore,1,NULL);
		LeaveCriticalSection(&m_csTaskQueue);
	}
};

这里我用到了一个信号量和一个临界区来保证线程安全,信号量的作用是每有一个执行的对象加入队列,就+1,反之就-1,然后利用WaitforSingleObject来让所有线程等待。临界区就不用说了,这是为了保证MyTask对象的队列的线程安全的。

最后附上线程池源码下载地址http://download.csdn.net/detail/yuguanquan1990/8109379


阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
C++线程池可以用来处理一些需要并发执行的任务,同时避免频繁创建和销毁线程所带来的开销。下面是一个简单的C++线程池实现: ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> class ThreadPool { public: ThreadPool(size_t num_threads) { for (size_t i = 0; i < num_threads; ++i) { threads_.emplace_back([this] { while (true) { Task task; { std::unique_lock<std::mutex> lock(mutex_); cond_.wait(lock, [this] { return !tasks_.empty() || stop_; }); if (stop_ && tasks_.empty()) return; task = std::move(tasks_.front()); tasks_.pop(); } task(); } }); } } ~ThreadPool() { { std::unique_lock<std::mutex> lock(mutex_); stop_ = true; } cond_.notify_all(); for (auto& thread : threads_) { thread.join(); } } template <typename Func, typename... Args> void AddTask(Func&& func, Args&&... args) { auto task = std::bind(std::forward<Func>(func), std::forward<Args>(args)...); { std::unique_lock<std::mutex> lock(mutex_); tasks_.emplace(std::move(task)); } cond_.notify_one(); } private: using Task = std::function<void()>; std::vector<std::thread> threads_; std::queue<Task> tasks_; std::mutex mutex_; std::condition_variable cond_; bool stop_ = false; }; ``` 这个实现定义了一个ThreadPool类,构造函数中创建了指定数量的线程,并且每个线程都会从任务队列中获取任务并执行;析构函数中会通知所有线程停止执行,并等待所有线程退出;AddTask方法用于添加一个任务到任务队列中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yuguanquan1990

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

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

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

打赏作者

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

抵扣说明:

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

余额充值