1 背景
在多任务系统中,我们经常会通过多进程或多线程去协同完成一个任务,或重复完成相同逻辑的不同任务,对并发及实时响应又有较高要求,一般的方法时,我们当接收到一个任务请求后,创建线程,线程函数完成任务,线程退出,频繁的创建线程会增加系统的负担,不利于线统的性能,且不利于任务的扩展,对系统的负载不可控,所以我们通过线程池来解决上述问题,在系统启动时根据配置(通过系统负载能力预估配置)创建一定数量的线程,由线程池控制块统一管理,在系统退出时,统一销毁线程池和线程,线程池中的线程,通过读取任务队列,去执行任务,完成任务后,线程释放回池中,准备执行下一个任务。
##2 需求 ##
- 线程池在系统启动后创建,池中线程可通过配置文件修改,修改线程数后,重启系统生效。
- 线程池生命同期与系统相同,可并发的访问任务队列。
- 任务队列可以有多条,可按优先级划分队列,最多的8条任务队列,4个优先级。
- 任务队列中任务需包含三个原素,任务执行函数,任务输入参数,任务状态。
- 任务队列个数,队列深度,可配置,修改配置后,重启服务后生效。
3 设计
4 实现
interface IWorkerItem
{
/*增加引用*/
virtual unsigned long AddRef()=0;
/*减少引用*/
virtual unsigned long Release()=0;
/*任务处理函数*/
virtual void WorkerMain(void* pThis)=0;
};
#ifndef _WORK_ITEM_QUEUE_H_
#define _WORK_ITEM_QUEUE_H_
#include <queue>
#include <list>
#include "IWorkerItem.h"
using namespace std;
/*任务队列类型*/
typedef queue< IWorkerItem,list<IWorkerItem*> > WORKER_ITEM_QUEUE;
class WorkItemQueue
{
public:
WorkItemQueue();
~WorkItemQueue(void);
public:
/*增加任务到队列*/
bool PutItem(IWorkerItem* _iWork);
/*获取队列中任务*/
IWorkerItem* GetItem();
/*移除队列中任务*/
bool RemoveItem(IWorkerItem* _iWork);
/*清除队列中任务项*/
bool ClearItem();
/*获取队列大小*/
int GetWorkerQueueSize();
/*设置队列的大小*/
bool SetWorkerQueueSize(int nSize);
/*获取对列中的任务数*/
int GetWorkerItemCount();
/*设置队列中的任务数*/
bool SetQueueItemCount(int nSize);
public:
private:
/*任务队列*/
WORKER_ITEM_QUEUE worker_queue;
/*队列大小*/
int nQueSize;
/*队列中任务数*/
int nCount;
};
#include <stdio.h>
#include "WorkItemQueue.h"
WorkItemQueue::WorkItemQueue() :nCount(0),nQueSize(0)
{
}
WorkItemQueue::~WorkItemQueue(void)
{
}
bool WorkItemQueue::PutItem(IWorkerItem* _iWork)
{
if((worker_queue.size()>=nQueSize)||(!_iWork))
{
printf("the queue size is exceed expected......\n");
return false;
}
worker_queue.push(_iWork);
nCount++;
printf("the item is sucessed add into the queue cout:%d iWork:%ld\n",nCount,_iWork);
return true;
}
IWorkerItem* WorkItemQueue::GetItem()
{
if(!worker_queue.empty())
{
IWorkerItem* iwork=worker_queue.front();
worker_queue.pop();
nCount--;
printf("the item is sucessed pop the item cout:%d pWork:%ld \n",nCount,iwork);
return iwork;
}
printf("the queue is empty......\n");
return NULL;
}
bool WorkItemQueue::RemoveItem(IWorkerItem* _iWork)
{
printf("the WorkItemQueue::RemoveItem hv call......\n");
nCount=0;
return true;
}
bool WorkItemQueue::ClearItem()
{
/*清空队列中的元素,由于放的是指针,
需要一个一个的完成释放*/
nCount=0;
printf("the WorkItemQueue::ClearItem hv call......\n");
return true;
}
int WorkItemQueue::GetWorkerQueueSize()
{
printf("the WorkItemQueue::GetWorkerQueueSize hv call......\n");
return nQueSize;
}
bool WorkItemQueue::SetWorkerQueueSize(int nSize)
{
printf("the WorkItemQueue::SetWorkerQueueSize hv call......\n");
nQueSize=nSize;
return true;
}
int WorkItemQueue::GetWorkerItemCount()
{
return nCount;
}
bool WorkItemQueue::SetQueueItemCount(int nSize)
{
nCount=nSize;
return true;
}
#ifndef _TTS_THREAD_POOL_H_
#define _TTS_THREAD_POOL_H_
#include <pthread.h>
#include <string>
#include "WorkItemQueue.h"
using namespace std;
class TTSThreadPool
{
public:
TTSThreadPool(int nThreads,int qSize);
virtual ~TTSThreadPool(void);
public:
/*创建Worker线程池*/
bool ThreadpoolCreate(int flags);
/*增加工作任务*/
int ThreadpoolAdd(IWorkerItem* worker_item);
/*销毁任务线程*/
int ThreadpoolDestroy();
/*释放线程池*/
int ThreadpoolFree();
/*获取工作队列实例*/
WorkItemQueue& GetWorkItemQueue();
/*获取线程数*/
int GetThreadCount();
/*设置任务队列关闭*/
int ShutDownWorkerQueue();
/*获取队列关闭状态*/
int IsWorkerQueueShutDown();
public:
static void* threadpool_thread(void *pThis);
public:
/*线程池同步锁*/
pthread_mutex_t lock;
/*任务队列*/
pthread_cond_t notify;
/*任务队列*/
int started;
/*任务队列*/
int shutdown;
private:
/*任务对列*/
WorkItemQueue worker_item_queue;
/*线池中程数*/
int nThreadCount;
/*线池中线程句柄*/
pthread_t *threads;
};
#endif
#include <stdlib.h>
#include "logger.h"
#include "TTSThreadPool.h"
TTSThreadPool::TTSThreadPool(int nThreads,int qSize):nThreadCount(nThreads),shutdown(0),started(0),threads(0)
{
worker_item_queue.SetWorkerQueueSize(qSize);
worker_item_queue.SetQueueItemCount(0);
}
TTSThreadPool::~TTSThreadPool(void)
{
if(!ThreadpoolFree())
{
LOG_ERROR("Free threadpool failed.");
}
if(!ThreadpoolDestroy())
{
LOG_ERROR("Destroy threadpool failed.");
}
}
bool TTSThreadPool::ThreadpoolCreate(int flags)
{
if(nThreadCount <= 0 || nThreadCount > MAX_THREADS_NUM || worker_item_queue.GetWorkerQueueSize() <= 0 || worker_item_queue.GetWorkerQueueSize() > MAX_QUEUE_ITEM_SIZE)
{
LOG_ERROR("Thread Pool Parameter Check error:nThreadCout:%d,nQueueSize:%d",nThreadCount,0);
return false;
}
this->threads = (pthread_t *)malloc(sizeof(pthread_t) * nThreadCount);
if((pthread_mutex_init(&(this->lock), NULL) != 0) ||(pthread_cond_init(&(this->notify), NULL) != 0) ||(this->threads == NULL))
{
LOG_ERROR("pthread_mutex_init && pthread_cond_init init failed,threads mem:%ld",threads);
int nRet=ThreadpoolFree();
return false;
}
/* 启动 Workerer 线程 */
for(int i = 0; i < nThreadCount; i++)
{
if(pthread_create(&(this->threads[i]), NULL,threadpool_thread, (void*)this) != 0)
{
LOG_ERROR("The thread %d is create failed...",i);
ThreadpoolDestroy();
return false;
}
this->started++;
LOG_INFO("I hv success create %d thread and the thread %d hv started",i,this->started);
}
return true;
}
int TTSThreadPool::ThreadpoolAdd(IWorkerItem* worker_item)
{
int err = THREADPOOL_ERRORNONE;
if(worker_item == NULL)
{
LOG_ERROR("the workitem is empty......");
return THREADPOOL_INVALID;
}
if(pthread_mutex_lock(&(this->lock)) != 0)
{
LOG_ERROR("Queue lock is init failed...");
return THREADPOOL_LOCK_FAILURE;
}
do {
LOG_INFO("start to add item into the queue...");
/* 判断队列是否已满 */
if(this->GetWorkItemQueue().GetWorkerItemCount() == this->worker_item_queue.GetWorkerQueueSize())
{
LOG_ERROR("The Queue is full..... pls check...");
err = THREADPOOL_QUEUE_FULL;
break;
}
/* 判断内存池是否关闭 */
if(this->shutdown)
{
LOG_ERROR("the queue is shutdown.....");
err = THREADPOOL_SHUTDOWN;
break;
}
/* 增加任务到队列 */
this->GetWorkItemQueue().PutItem(worker_item);
/*设置队列信号 */
if(pthread_cond_signal(&(this->notify)) != 0)
{
LOG_INFO("I hv notify the others......");
err = THREADPOOL_LOCK_FAILURE;
break;
}
} while(0);
if(pthread_mutex_unlock(&this->lock) != 0)
{
LOG_ERROR("Unlock the queue......");
err = THREADPOOL_LOCK_FAILURE;
}
return err;
}
int TTSThreadPool::ThreadpoolDestroy()
{
int i, err = 0;
if(pthread_mutex_lock(&(this->lock)) != 0)
{
return THREADPOOL_LOCK_FAILURE;
}
do {
/* 已经关闭 */
if(this->shutdown)
{
err = THREADPOOL_SHUTDOWN;
break;
}
this->shutdown = 1 ;
/* 唤醒所有工作线程 */
if((pthread_cond_broadcast(&(this->notify)) != 0) ||
(pthread_mutex_unlock(&(this->lock)) != 0))
{
err = THREADPOOL_LOCK_FAILURE;
break;
}
/* Join 工作线程 */
for(i = 0; i < this->nThreadCount; i++)
{
if(pthread_join(this->threads[i], NULL) != 0) {
err = THREADPOOL_THREAD_FAILURE;
}
}
} while(0);
/* 释放线程池 */
if(!err)
{
ThreadpoolFree();
}
return err;
}
int TTSThreadPool::ThreadpoolFree()
{
LOG_ERROR("GetWorkItemQueue is called......");
if( this->started > 0)
{
return -1;
}
/* 释放线程,清空队列 */
if(this->threads)
{
free(this->threads);
this->threads=NULL;
this->worker_item_queue.ClearItem();
/*锁住线程,防止最后冲突*/
pthread_mutex_lock(&(this->lock));
pthread_mutex_destroy(&(this->lock));
pthread_cond_destroy(&(this->notify));
}
return 0;
}
WorkItemQueue& TTSThreadPool::GetWorkItemQueue()
{
return worker_item_queue;
}
int TTSThreadPool::GetThreadCount()
{
return nThreadCount;
}
int TTSThreadPool::ShutDownWorkerQueue()
{
this->shutdown=1;
}
int TTSThreadPool::IsWorkerQueueShutDown()
{
return this->shutdown;
}
void* TTSThreadPool::threadpool_thread(void *pThis)
{
TTSThreadPool *pPool = (TTSThreadPool*)pThis;
IWorkerItem* task=NULL;
for(;;)
{
pthread_mutex_lock(&(pPool->lock));
/* 等待notify 变为受信状态*/
while((pPool->GetWorkItemQueue().GetWorkerItemCount() == 0) && (!pPool->shutdown))
{
LOG_INFO("----------------i am waiting-----------------");
pthread_cond_wait(&(pPool->notify), &(pPool->lock));
}
if((pPool->shutdown == 1) ||((pPool->shutdown == 1) &&(pPool->GetWorkItemQueue().GetWorkerItemCount() == 0)))
{
LOG_INFO("------------pool shutdown&&empty--------------");
break;
}
/* 任务出列,准备开始工作 */
task=(pPool->GetWorkItemQueue()).GetItem();
/* 工作队列减锁 */
pthread_mutex_unlock(&(pPool->lock));
/* 任务开始工作*/
task->WorkerMain((void*)task);
sleep(0);
}
pPool->started--;
pthread_exit(NULL);
return NULL;
}