C++线程池

来源:互联网 发布:备案好的域名买卖 编辑:程序博客网 时间:2024/06/05 19:10

C++线程池

1.技术背景

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。

2.组成部分

服务器程序利用线程技术响应客户请求已经司空见惯,可能您认为这样做效率已经很高,但您有没有想过优化一下使用线程的方法。该文章将向您介绍服务器程序如何利用线程池来优化性能并提供一个简单的线程池实现。


1、线程池管理器(ThreadPoolManager):用于创建并管理线程池

2、工作线程(WorkThread): 线程池中线程

3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。

4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。

3.示例

本文线程池的实现,依赖于《C++线程类》,建议先移步了解一下!

为了确保多线程环境下ThreadPoolManager数据访问安全,设计CGuard类,它是对Winwows临界区对象的封装,用于线程互斥访问临界资源。

#ifndef _H_CGUARD_H_#define _H_CGUARD_H_#include <Windows.h>class CGuard{public:CGuard();~CGuard();void Enter();void Leave();public:class Guard{public:Guard(CGuard& guard);~Guard();private:CGuard& m_Guard;};private:CRITICAL_SECTION m_cs;};CGuard::CGuard(){InitializeCriticalSection(&m_cs);}CGuard::~CGuard(){DeleteCriticalSection(&m_cs);}void CGuard::Enter(){EnterCriticalSection(&m_cs);}void CGuard::Leave(){LeaveCriticalSection(&m_cs);}CGuard::Guard::Guard( CGuard& guard ):m_Guard(guard){m_Guard.Enter();}CGuard::Guard::~Guard(){m_Guard.Leave();}#endif

RandomDataFileCreater类定义TaskThread任务,此处完成的功能是写入一定的随机数到一个随机文件名的TXT文档中。

#ifndef _H_RANDOM_DATA_FILE_CREATER_H_#define _H_RANDOM_DATA_FILE_CREATER_H_#include <iostream>#include <string>#include <fstream>#include <assert.h>#include "Runnable.h"#include "CGuard.h"class RandomDataFileCreater:public Runnable{public:RandomDataFileCreater(unsigned int count);void Run();private:std::string m_FilePath;unsigned int m_count;static CGuard m_guard;};CGuard RandomDataFileCreater::m_guard;RandomDataFileCreater::RandomDataFileCreater( unsigned int count ):m_count(count){char charr[80] = {};itoa(rand(), charr, 10);m_FilePath = charr;m_FilePath.append(".txt");assert(m_FilePath.length());}void RandomDataFileCreater::Run(){if (m_FilePath.length() < 1){std::cout << "RandomDataFileCreater::Run: " << m_count << std::endl;return ;}std::ofstream outFileObj(m_FilePath);if (outFileObj.good()){for (int i=0; i!=m_count; ++i){outFileObj << rand() << std::endl;}}else{std::cout << "Error: " << m_FilePath << "\t" << m_count << std::endl;}}#endif

上代码,配合注释直接看吧。

#ifndef _H_AKMTHREAD_H_#define _H_AKMTHREAD_H_#include <Windows.h>#include <set>#include <list>#include "Runnable.h"#include "CThread.h"#include "CGuard.h"class ThreadPoolManager{public:ThreadPoolManager();~ThreadPoolManager();/**初始化线程池@arg minThreads最少的线程数@arg maxThreads最大的线程数@arg maxpendingTasks最大的等待任务数**/bool Init(unsigned int minThreads, unsigned int maxThreads, unsigned int maxpendingTasks);/**执行一个任务@arg pRunnable 指向任务的指针**/bool Execute(Runnable* pRunnable);/**终止线程池运行 (等待池内线程运行完毕)**/void Terminate();/**获取当前有效线程数**/unsigned int ThreadPoolSize();private:/**获取任务队列中的一个任务 (FIFO)**/Runnable* GetTask();private:class CWorker:public CThread{public:CWorker(ThreadPoolManager* pThreadPool, Runnable* pFirstTask = NULL);virtual ~CWorker();virtual void Run();void Restore(Runnable* pTask = NULL);private:ThreadPoolManager* m_pThreadPool;Runnable* m_FirstTask;volatile bool m_bRun;};typedef std::set<CWorker*> ThreadsPool;typedef std::list<Runnable*> Tasks;typedef Tasks::iterator TasksIter;typedef ThreadsPool::iterator ThreadPoolIter;private:volatile bool m_bRun;volatile bool m_bCanInsertTask;volatile unsigned int m_minThreads;volatile unsigned int m_maxThreads;volatile unsigned int m_maxPendingTasks;ThreadsPool m_ThreadPool;ThreadsPool m_TrashThreads;Tasks m_Tasks;CGuard m_TasksGuard;CGuard m_ThreadsGuard;CGuard m_TrashThreadsGuard;CGuard m_CoutGuard;};ThreadPoolManager::ThreadPoolManager():m_bRun(false),m_bCanInsertTask(false){NULL;}ThreadPoolManager::~ThreadPoolManager(){Terminate();}bool ThreadPoolManager::Init( unsigned int minThreads, unsigned int maxThreads, unsigned int maxpendingTasks ){//参数逻辑检测if (minThreads < 1 || maxThreads < minThreads || maxpendingTasks < 1){return false;}m_minThreads = minThreads;m_maxThreads = maxThreads;m_maxPendingTasks = maxpendingTasks;//创建并启动初始线程for (int i=0; i!=minThreads; ++i){CWorker* pWorker = new CWorker(this);if (NULL ==pWorker){continue;}else{CGuard::Guard g(m_ThreadsGuard);m_ThreadPool.insert(pWorker);pWorker->Start();{CGuard::Guard g(m_CoutGuard);std::cout << "Init Thread: " << pWorker->ThreadID() << std::endl;}}}m_bRun = true;m_bCanInsertTask = true;return true;}bool ThreadPoolManager::Execute( Runnable* pRunnable ){if (!m_bCanInsertTask){return false;}if (NULL == pRunnable){return false;}//任务队列溢出时CGuard::Guard g(m_TasksGuard);if (m_Tasks.size() >= m_maxPendingTasks){//有闲置的线程可用 重新启用一个CGuard::Guard g2(m_ThreadsGuard);CGuard::Guard g3(m_TrashThreadsGuard);if (m_TrashThreads.size() > 0){ThreadPoolIter iter = m_TrashThreads.begin();if (iter != m_TrashThreads.end()){m_ThreadPool.insert(*iter);(*iter)->Restore(pRunnable);{CGuard::Guard g(m_CoutGuard);std::cout << "Restore Worker On Execute: " << (*iter)->ThreadID() << std::endl;}m_TrashThreads.erase(iter);return true;}else{CGuard::Guard g(m_CoutGuard);std::cout << "------Error " << std::endl;return false;}}else if (m_ThreadPool.size() < m_maxThreads){//无闲置线程  若可创建新线程 则创建并启动此次任务的线程CWorker* pWorker = new CWorker(this, pRunnable);if (NULL == pWorker){return false;}else{CGuard::Guard g(m_ThreadsGuard);m_ThreadPool.insert(pWorker);pWorker->Start();{CGuard::Guard g(m_CoutGuard);std::cout << "New Worker On Execute: " << pWorker->ThreadID() << std::endl;}}}else{return false;}}else{//未溢出 则入队m_Tasks.push_back(pRunnable);}return true;}void ThreadPoolManager::Terminate(){//阻止新的任务加入m_bCanInsertTask = false;//等待直到任务队列被线程拿空while(m_Tasks.size() > 0){Sleep(100);}//重置线程池指标数据 以便最后一批线程执行后转移到trashThreadsm_bRun = false;m_minThreads = 0;m_maxThreads = 0;m_maxPendingTasks = 0;//等待所有在执行的线程执行完毕while(m_ThreadPool.size() > 0){Sleep(1);}//清理线程执行后转移到TrashThreads的线程CGuard::Guard g(m_ThreadsGuard);ThreadPoolIter iter = m_TrashThreads.begin();while(iter != m_TrashThreads.end()){(*iter)->Join();delete (*iter);m_TrashThreads.erase(iter);iter = m_TrashThreads.begin();}}unsigned int ThreadPoolManager::ThreadPoolSize(){return m_ThreadPool.size();}Runnable* ThreadPoolManager::GetTask(){Runnable* pTask = NULL;CGuard::Guard g(m_TasksGuard);if (!m_Tasks.empty()){pTask = m_Tasks.front();m_Tasks.pop_front();}return pTask;}ThreadPoolManager::CWorker::CWorker( ThreadPoolManager* pThreadPool, Runnable* pFirstTask /*= NULL*/ ):m_pThreadPool(pThreadPool),m_FirstTask(pFirstTask),m_bRun(true){NULL;}ThreadPoolManager::CWorker::~CWorker(){m_pThreadPool = NULL;m_FirstTask = NULL;m_bRun = false;}void ThreadPoolManager::CWorker::Run(){Runnable* pTask = NULL;while(m_bRun){//循环获取任务去执行 if (NULL == pTask){pTask = m_pThreadPool->GetTask();}else{pTask = m_FirstTask;m_FirstTask = NULL;}if (NULL == pTask){CGuard::Guard g(m_pThreadPool->m_ThreadsGuard);if (m_pThreadPool->ThreadPoolSize() > m_pThreadPool->m_minThreads){//任务不足 线程闲置 转移至m_TrashThreads 置位闲置ThreadPoolIter iter = m_pThreadPool->m_ThreadPool.find(this);if (m_pThreadPool->m_ThreadPool.end() != iter){m_pThreadPool->m_TrashThreads.insert(*iter);{CGuard::Guard g(m_pThreadPool->m_CoutGuard);std::cout << "Idle On Run: " << ThreadID() << std::endl;}m_pThreadPool->m_ThreadPool.erase(iter);}m_bRun = false;}else{//线程池Terminate之后 任务执行完毕 自清理所有闲置线程CGuard::Guard g(m_pThreadPool->m_TrashThreadsGuard);ThreadPoolIter iter = m_pThreadPool->m_TrashThreads.begin();while(iter != m_pThreadPool->m_TrashThreads.end()){{CGuard::Guard g(m_pThreadPool->m_CoutGuard);std::cout << "Self Clean: " << (*iter)->ThreadID() << std::endl;}(*iter)->Join();delete (*iter);m_pThreadPool->m_TrashThreads.erase(iter);iter = m_pThreadPool->m_TrashThreads.begin();}}continue;}else{CGuard::Guard g(m_pThreadPool->m_CoutGuard);std::cout << "Run : " <<  ThreadID() << std::endl;pTask->Run();pTask = NULL;}}}void ThreadPoolManager::CWorker::Restore( Runnable* pTask /*= NULL*/ ){m_FirstTask = pTask;m_bRun = true;Run();}#endif

4.场景测试

#include <iostream>#include <Windows.h>#include <list>#include <algorithm>#include "ThreadPoolManager.h"#include "RandomDataFileCreater.h"using namespace std;int main(int argc, char* argv[]){srand(GetTickCount64());{//创建并初始化线程池ThreadPoolManager* tpMgr = new ThreadPoolManager();tpMgr->Init(1, 10, 20);//创建任务列表list<RandomDataFileCreater*> rdfcList;for (int i=0; i!=100; ++i){rdfcList.push_back(new RandomDataFileCreater(i * i + 5));}//模拟突发任务提交到线程池int cnt = 0;list<RandomDataFileCreater*>::iterator iter = rdfcList.begin();for ( ; iter != rdfcList.end(); ++iter){++cnt;while(!tpMgr->Execute(*iter));if (40 < cnt && cnt < 60){Sleep(rand() % 357);}}//终止线程池tpMgr->Terminate();//清理任务指针iter = rdfcList.begin();for ( ; iter != rdfcList.end(); ++iter){delete *iter;}//清理线程池对象指针delete tpMgr;}system("pause");return 0;}

为了方便观察线程池的运作,代码添加了相关调试代码输出相关信息。当然,如果不需要是可以删除或者注释掉的。另外说明一下,测试代码里面的 while(!tpMgr->Execute(*iter)) 是为了确保每个创建的任务提交并成功执行到位。而语句 if (40 < cnt && cnt < 60) 里面去 Sleep(rand() % 357) 则是为了相对真实的模拟突发任务请求。






0 0