2006转眼就要过去了,今天是2006年最后一天,特此总结一下关于线程池的设计与实现,与各位大虾共享,也算是给所有认识的、不认识的朋友,一个小小礼物。嘎嘎。
言归正传,我们先来说说线程池的相关概念。
一、什么是池。
池的英文名:POOL,可以理解个容器,一个水缸。打个比方,我小时住在农村,家里都有个水缸,父母会每天早上从湖里,跳水倒满水缸,这样一天的生活用水就准备好了。当我们用水的时候,只需要从水缸里,舀水即可,而不用从湖里去取。这样你现在也许就会明白了,有了池,效率明显高了。在软件中,存在多种池,如线程池,内存池,数据库连接池等等。根据实现的软件需求,这些池将极大提高软件效率。
二、什么线程池
上面我们讲述了什么池,那么现在来说明一下,什么是线程池。线程池,也就是在这个池里,预先放入一些线程,以后后来方便使用。
三、为什么要使用线程池
我们都知道线程的频繁创建、销毁,是需要耗费一点的系统资源的,所以预先创建一系列空线程,需要使用线程时,从线程池里,获取IDLE线程,这样执行起来效率就非常高了,也便于管理。
四、线程池需要具备的几个元素
1) 线程池要有个列表,来管理多个线程对象。
2) 线程池要提供获取空闲(IDLE)线程方法
3) 线程池中的线程,具体执行的内容,可自定义。
4) 线程池中的线程,使用完毕后,还能被收回,供下次使用。
下面是我简要来设计线程池如何实现,朋友们可以根据此版本进行扩充或者改进。本BLOG所讲述的线程池实现主要包含3个类:
1) TEricThreadManager
线程管理类,此对象在创建时,并默认创建N个CEricWorkThread线程,并且这些线程状态都是IDLE,表示都可以被使用的。
方法JoinTask,是TEricThreadManager非常重要的方法,用于向线程池中,提取一个空闲(IDLE)线程,执行某个特定的任务。
实现如下:
//加入一个任务
bool CEricThreadPoolManager::JoinTask(CEricThread* pEricThreadObj)
{
CEricWorkThread *pEricWorkThread = GetIdleThread();
if (pEricWorkThread == NULL)
{
return FALSE;
}
pEricWorkThread->RunTask(pEricThreadObj);
return TRUE;
}
方法GetIdleThread,用于从线程队列中,获取一个空闲线程使用。此方法在线程池的设计中,也是必不可少的。
//得到空闲线程
CEricWorkThread* CEricThreadPoolManager::GetIdleThread()
{
POSITION pos = NULL;
CEricWorkThread *pEricWorkThread = NULL;
for( pos = m_lstThreads.GetHeadPosition(); pos != NULL; )
{
pEricWorkThread = (CEricWorkThread *)m_lstThreads.GetNext( pos );
if (pEricWorkThread->IsIdle())
{
return pEricWorkThread;
}
}
return NULL;
}
2) CEricWorkThread
刚才我们讲述了,线程池中的“线程管理类”,现在我们接着来讲述一下,线程池另外非常重要的类CEricWorkThread,它其实就是一个线程类。在CEricWorkThread类对象创建时,自动创建一个线程实例,此时此线程是个空线程。此线程实现如下:
//工作线程
DWORD WINAPI CEricWorkThread::DefaultJobProc(LPVOID lpParameter )
{
CEricWorkThread *pThis = (CEricWorkThread*)lpParameter;
HANDLE hWaitHandle[2];
hWaitHandle[0] = pThis->m_hEventRun;
hWaitHandle[1] = pThis->m_hEventExit;
for(;;)
{
DWORD wr = WaitForMultipleObjects(2, hWaitHandle, false, INFINITE);
if (wr == WAIT_OBJECT_0) //执行RUN
{
pThis->m_bIdle = FALSE; //线程不空闲
pThis->m_pRunObject->Run();
//释放此对象
delete pThis->m_pRunObject;
pThis->m_pRunObject = NULL;
pThis->m_bIdle = TRUE; //线程空闲
}
else if (wr == WAIT_OBJECT_0+1) //退出线程
{
break;
}
}
return 0;
}
我们看到,当线程需要执行某个特定任务时,调用下面的语句来执行。
pThis->m_pRunObject->Run();
CEricWorkThread类有个非常重要的方法
bool RunTask(CEricThread *pEricThread);
用来制定特定的任务,并执行此任务。
3) TEricThread
TEricThread类是具体任务执行类的基类,它有个虚方法
//线程函数中执行体
virtual void Run()=0;
来表示具体动作。
我们可以通过继承TEricThread类,来自定义各种动作。
线程池中的核心类,就介绍完毕了。朋友们可以根据如上所说,来搭建自己的线程池。
--------------------------------------------------------
by victor:
linux下也可以按照这样的思路来设计线程池。