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;
}