线程池

一、设计缘由:

1. 当程序需要诸多可并行执行的任务需要执行时,有必要考虑使用多线程。
2.线程的创建与切换上下文占用大量的时间开销,有必要进行管理,不能无限制增加线程。


二、具体描述:

1.总体设计

线程池初始化一定数量的线程个数,在没有任务分派的时候,各个线程挂起,这样并不占用CPU资源,不会影响程序的性能。当有任务队列中有任务需要处理时,将某一线程从空闲线程链表中摘取一个线程去执行该任务,等该线程完成了当前任务后,去线程池中查找是否还有其他任务被派遣,若有则取之执行,若无则当前无需线程执行任务,那么当前线程挂起,转存至空闲线程栈中,在线程池声明周期内重复此过程。如客户端欲销毁线程池,先通知各线程退出,然后销毁任务队列中尚未操作的任务,此时更改线程池状态为已销毁,其他线程此时再往线程池中投放任务,将不做处理,并返回失败。


2.具体设计

(1).线程池: 线程池维护任务、忙碌线程、空闲线程三种列表具体如下:

(a).任务队列:对于需要处理的任务,采用先来先服务算法,故采取队列存储之;
(b).忙碌线程链表:对于忙碌线程考虑可能会频繁转化线程状态,即可能从忙碌链表中删除,添加到空闲线程栈中, 故采取添加删除节点效率比较高的链表结构存  储之;
(c).空闲线程栈:对于空闲线程,根据局部性原理,刚执行完的线程所占有的内存等资源还在内存中的概率比较大,即内存命中率高,有效的防止换页的开销,故 采取栈结构存储之。

(2).线程: 从线程池中的任务队列中取任务执行,在无任务执行时挂起。
(3).任务:  继承统一接口,供线程池中线程调用。

(4).临界锁:保证列表以及其他独占资源的互斥保护。


三、具体源码:


        由于部分类名可能与某些库的名称重名故使用命名空间 thead_pool,另外对于面向对象编程,应该面向接口编程,如下定义了一些接口。


1.任务接口,欲使用线程池的任务须继承该接口,以便在线程中可以进行调度该任务。


namespace thead_pool
{
interface IThreadTask
{
virtual void ProcessTask()  =  0;
};
}


       2.线程类

       抽象线程类有如下接口,线程应该有创建、以及通知其退出的接口,另外作为线程池中的线程类,应该有向线程池中请求任务的接口,故线程接口如下:

       namespace thead_pool
{
interface IThreadTask;
interface IThread
{
// 创建线程
virtual void CreateThread() = 0;

// 通知线程退出
virtual void NotifyThreadExit() = 0;

// 线程执行实体
virtual void Run() = 0;

// 给线程安排任务:由于每次线程池分派任务,必然是从空闲线程列表中摘取线程, 而该列表互斥保护,故此函数不会被重入,不需加锁
virtual void AssignTask(IThreadTask *pTask) = 0;
};
}


        具体线程类,线程在未等到任务到来时应处于挂起状态,这样才不会占用cpu等资源,不会影响到程序的性能,定义了该通知事件,另外线程应该保存线程池的指针, 这样才能在当前任务完成后去查询是否还有任务需要执行,另外定义了线程是否自删除属性,以便于清理线程资源。

   

       namespace thead_pool
{
interface IThreadPool;
class CThread:public IThread
{
public:
CThread(IThreadPool *pThreadPool, BOOL bAutoDelete = TRUE);
~CThread(void);
virtual void CreateThread();
virtual void NotifyThreadExit();
virtual void Run();
virtual void AssignTask(IThreadTask *pTask);
static unsigned int __stdcall ProcThread(void *pParam);

private:
// 创建任务通知事件
void CreateTaskNotifyEvent();


// 线程是否自运行完成后自销毁
BOOL m_bAutoDelete;
// 线程是否在运行
BOOL m_bRunning;
// 线程句柄
HANDLE m_hThread;
// 事件通知句柄,用以同步任务的到来
HANDLE m_hEventTaskArrive;
// 保存线程池指针,当执行完当前任务后,回收当前线程到空闲线程栈
IThreadPool* m_pThreadPool;
// 当前执行的任务指针
IThreadTask* m_pThreadTask; 
};
}

// 具体实现如下:

namespace thead_pool
{
CThread::CThread(IThreadPool *pThreadPool,BOOL bAutoDelete)
:m_hThread(NULL)
,m_hEventTaskArrive(NULL)
,m_pThreadPool(pThreadPool)
,m_bRunning(FALSE)
,m_pThreadTask(NULL)
,m_bAutoDelete(bAutoDelete)
{
CreateTaskNotifyEvent();
CreateThread();
}


CThread::~CThread(void)
{
CloseHandle(m_hThread);
CloseHandle(m_hEventTaskArrive);
}

void CThread::CreateTaskNotifyEvent()
{
m_hEventTaskArrive = CreateEvent(NULL,TRUE,FALSE,L"");
}


void CThread::CreateThread()
{
m_bRunning = TRUE;
m_hThread = (HANDLE)_beginthreadex(NULL,0,ProcThread,this,0,NULL);
}


void CThread::NotifyThreadExit()
{
m_bRunning = FALSE;
SetEvent(m_hEventTaskArrive);
WaitForSingleObject(m_hThread,INFINITE);
}


void CThread::Run()
{
while(TRUE)
{
//倘若没有任务到来,那么本线程挂起,不占用cpu等资源
DWORD dwWaitResult =  WaitForSingleObject(m_hEventTaskArrive, INFINITE);
// 如果等到了,先把手头的任务做完,再看是否已被通知退出
if (WAIT_OBJECT_0 == dwWaitResult)
{
// 需要重置事件,以便下次使用
ResetEvent(m_hEventTaskArrive);

// 如果有任务那么去处理任务
if (NULL != m_pThreadTask)
{
m_pThreadTask->ProcessTask();
delete m_pThreadTask;
m_pThreadTask = NULL;
}


// 如果此时已被通知退出,那么不再索要任务了,回收本线程到空闲线程栈
m_pThreadPool->AssignNextTask(!m_bRunning,this);

}
// 等失败了,出现了某些情况?
else if (WAIT_FAILED == dwWaitResult)
{
// 线程池通知线程退出
if (!m_bRunning)
{
// 如果此时已被通知退出,回收本线程到空闲线程栈
m_pThreadPool->AssignNextTask(TRUE,this);
break;
}
}


// 线程已被回收到空闲线程栈,本线程可以安心退出了
if (!m_bRunning)
break;
}

if(m_bAutoDelete)
{
delete this;
}
}


// 该函数由外部线程队列维护互斥,不会重入
void CThread::AssignTask(IThreadTask *pTask)
{
m_pThreadTask = pTask;
SetEvent(m_hEventTaskArrive);
}


unsigned int __stdcall CThread::ProcThread(void *pParam)
{
CThread *pThread = (CThread*)pParam;
pThread->Run();

return 0;
}
}

       3.线程池类

       线程池接口,线程池应提供初始化,以及销毁接口,另外需开放任务投放接口

       namespace thead_pool
{
interface IThreadTask;
interface IThread;

interface IThreadPool
{
// 初始化线程池,需指定线程池中线程个数
virtual void InitThreadPool(int nThreadCounts) = 0;


// 销毁线程池,注意次序:先通知线程退出,待线程退出后销毁线程对象,再去释放尚未完成的任务对象
virtual void DestoryThreadPool() = 0;


// 线程池是否已经销毁,此时不能再向线程池投放任务
virtual BOOL IsThreadPoolDestoryed() = 0;


// 向线程池中投放任务,添加之前查询线程池是否已被销毁,若已被销毁返回FALSE,调用者需要销毁任务
virtual BOOL AddTask(IThreadTask *pTask) = 0;


// 取得任务队列中下一个任务
virtual IThreadTask* GetNextTask() = 0;


// 从任务队列中获取下一个任务给该线程,若队列为空或者只是想回收线程,那么将线程放入空闲队列
virtual void AssignNextTask(BOOL bJustChangeState ,IThread *pThread) = 0;
};
}

       具体线程池类:线程池除了维护空闲线程、忙碌线程、任务列表外,还要记录线程池状态,当线程池处于销毁状态时,不能再投放线程

      
namespace thead_pool
{
interface IThreadPool;
class CThreadPool:public IThreadPool
{

public:
CThreadPool();
~CThreadPool();

virtual BOOL AddTask(IThreadTask *pTask);
virtual void InitThreadPool(int nThreadCounts);
virtual void DestoryThreadPool();

protected:
virtual BOOL IsThreadPoolDestoryed();
virtual IThreadTask* GetNextTask();
virtual void AssignNextTask(BOOL bJustChangeState,IThread *pThread);

private:
// 线程池是否已被销毁
BOOL m_bThreadPoolDestoryed;
// 线程池状态锁
ILock* m_pPoolStatusLock;

// 空闲线程栈
CIdleThreadStack m_idleThreadStack;
// 运行线程列表
CBusyThreadList  m_busyThreadList;
// 任务队列
CTaskQueue m_taskQueue;
};
}

       具体实现如下:

       namespace thead_pool
{
CThreadPool::CThreadPool()
:m_bThreadPoolDestoryed(FALSE)
,m_pPoolStatusLock(NULL)
{
}


CThreadPool::~CThreadPool()
{
delete m_pPoolStatusLock;
m_pPoolStatusLock = NULL;
}

BOOL CThreadPool::IsThreadPoolDestoryed()
{
m_pPoolStatusLock->Lock();
BOOL bDestoryed = m_bThreadPoolDestoryed;
m_pPoolStatusLock->UnLock();
return bDestoryed;
}

void CThreadPool::InitThreadPool(int nThreadCounts)
{
m_pPoolStatusLock = new CCriticalLock();

for (int indexThread = 0;indexThread < nThreadCounts;++ indexThread)
{
IThread *pThread = new CThread(this);
m_idleThreadStack.AddIdleThread(pThread);
}
}
   
BOOL CThreadPool::AddTask(IThreadTask *pTask)
{
if (IsThreadPoolDestoryed())
return FALSE;


m_taskQueue.AddThreadTask(pTask);
IThread *pThread = m_idleThreadStack.PopIdleThread();
if (NULL != pThread)
{
pThread->AssignTask(m_taskQueue.GetThreadTask());
m_busyThreadList.AddBusyThread(pThread);
}
return TRUE;
}


IThreadTask* CThreadPool::GetNextTask()
{
return m_taskQueue.GetThreadTask();
}


void CThreadPool::DestoryThreadPool()
{
m_pPoolStatusLock->Lock();
m_bThreadPoolDestoryed = TRUE;
m_pPoolStatusLock->UnLock();

m_busyThreadList.CleanAllBusyThreads();
m_idleThreadStack.CleanAllIdleThreads();
m_taskQueue.CleanAllTask();
}

void CThreadPool::AssignNextTask(BOOL bJustChangeState, IThread *pThread)
{
if (IsThreadPoolDestoryed())
return;

if (bJustChangeState || m_taskQueue.IsTaskAllComplete())
{
m_busyThreadList.DeleteBusyThread(pThread);
m_idleThreadStack.AddIdleThread(pThread);
}
else
{
pThread->AssignTask(GetNextTask());
}
}
}

       4.其他类

      a.互斥锁,保证独占资源的互斥访问

       namespace thead_pool
{
interface ILock
{
// 锁定互斥资源
virtual void Lock()  = 0;
// 释放互斥资源
virtual void UnLock() = 0;
};
}

       namespace thead_pool
{
class CCriticalLock:public ILock
{
public:
CCriticalLock(void);
~CCriticalLock(void);


virtual void Lock();
virtual void UnLock();
private:
CRITICAL_SECTION m_critcalSection;
};
}

b.任务队列

        namespace thead_pool
{
interface ILock;
interface IThreadTask;


class CTaskQueue
{
public:
CTaskQueue(void);
~CTaskQueue(void);
void AddThreadTask(IThreadTask *pThreadTask);
IThreadTask* GetThreadTask();
BOOL IsTaskAllComplete();
void CleanAllTask();
private:
ILock *m_pLock;
queue<IThreadTask*>m_threadTaskQueue;
};
}


namespace thead_pool
{
CTaskQueue::CTaskQueue(void)
{
m_pLock = new CCriticalLock();
}


CTaskQueue::~CTaskQueue(void)
{
delete m_pLock;
m_pLock = NULL;
}

void CTaskQueue::AddThreadTask(IThreadTask *pThreadTask)
{
m_pLock->Lock();
m_threadTaskQueue.push(pThreadTask);
m_pLock->UnLock();
}

IThreadTask* CTaskQueue::GetThreadTask()
{
IThreadTask *pThreadTask = NULL;
if (!m_threadTaskQueue.empty())
{
m_pLock->Lock();
pThreadTask = m_threadTaskQueue.front();
m_threadTaskQueue.pop();
m_pLock->UnLock();
}
return pThreadTask;
}


void CTaskQueue::CleanAllTask()
{
// 进行到这一步,不会再有任务添加进来,为空就不加锁了
if (!m_threadTaskQueue.empty())
{
m_pLock->Lock();
IThreadTask *pThreadTask = m_threadTaskQueue.front();
delete pThreadTask;
pThreadTask = NULL;
m_threadTaskQueue.pop();
m_pLock->UnLock();
}
}


BOOL CTaskQueue::IsTaskAllComplete()
{
m_pLock->Lock();
BOOL bAllComplete =  m_threadTaskQueue.empty();
m_pLock->UnLock();
return bAllComplete;
}
}

c.空闲线程链表:

       namespace thead_pool
{
interface IThread;
interface ILock;


class CIdleThreadStack
{
public:
CIdleThreadStack(void);
~CIdleThreadStack(void);
// 向空闲线程栈中添加线程
void AddIdleThread(IThread *pThread);
// 从空闲线程栈中取线程
IThread* PopIdleThread();
// 清理空闲线程
void CleanAllIdleThreads();
private:
ILock *m_pLock;
stack<IThread*>m_idleThreads;
};
}

具体实现如下:

       
namespace thead_pool
{
CIdleThreadStack::CIdleThreadStack(void)
{
m_pLock = new CCriticalLock();
}


CIdleThreadStack::~CIdleThreadStack(void)
{
delete m_pLock;
m_pLock = NULL;
}

void CIdleThreadStack::AddIdleThread(IThread *pThread)
{
m_pLock->Lock();
m_idleThreads.push(pThread);
m_pLock->UnLock();
}

IThread* CIdleThreadStack::PopIdleThread()
{
IThread *pThread = NULL;
if (!m_idleThreads.empty())
{
m_pLock->Lock();
pThread = m_idleThreads.top();
m_idleThreads.pop();
m_pLock->UnLock();
}
return pThread;
}


void CIdleThreadStack::CleanAllIdleThreads()
{
// 进行到这一步,不会再有线程添加进来,为空就不加锁了
if (!m_idleThreads.empty())
{
m_pLock->Lock();

IThread *pThread = m_idleThreads.top();

// 通知线程退出即可,让线程运行完自行销毁
pThread->NotifyThreadExit();
m_idleThreads.pop();
m_pLock->UnLock();
}
}
}

d.忙碌线程栈:

        namespace thead_pool
{
interface IThread;
interface ILock;
class CBusyThreadList
{
public:
CBusyThreadList(void);
~CBusyThreadList(void);
// 向运行线程列表中添加线程
void AddBusyThread(IThread* pThread);
// 从运行线程列表中删除线程
void DeleteBusyThread(IThread* pThread); 
// 清理运行线程
void CleanAllBusyThreads();
private:
ILock *m_pLock;
list<IThread*>m_busyThreadList;
};
}

        具体实现如下:



namespace thead_pool
{
CBusyThreadList::CBusyThreadList(void)
{
m_pLock = new CCriticalLock();
}

CBusyThreadList::~CBusyThreadList(void)
{
delete m_pLock;
m_pLock = NULL;
}

void CBusyThreadList::AddBusyThread(IThread* pThread)
{
m_pLock->Lock();
m_busyThreadList.push_back(pThread);
m_pLock->UnLock();
}

void CBusyThreadList::DeleteBusyThread(IThread* pThread)
{
if (!m_busyThreadList.empty())
{
m_pLock->Lock();
m_busyThreadList.remove(pThread);
m_pLock->UnLock();
}
}

void CBusyThreadList::CleanAllBusyThreads()
{
// 进行到这一步,不会再有线程添加进来,为空就不加锁了
if (!m_busyThreadList.empty())
{
m_pLock->Lock();
list<IThread*>::iterator first = m_busyThreadList.begin();
list<IThread*>::iterator last = m_busyThreadList.end();
for(;first!=last;++first)
{
// 通知线程退出即可,让线程运行完自行销毁
(*first)->NotifyThreadExit();
}
m_busyThreadList.clear();
m_pLock->UnLock();
}
}
}

四、总结:

使用线程去解决一些问题,能提高并发的效率,但多线程的处理有时有些繁琐,需考虑妥帖。以上是我设计的简单线程池模块,写的不好的地方还欢迎大家批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值