用百度搜索一下“Linux 线程池”,很出现很多个结果,有的提供的源程序是可以使用的,但仔细分析后,发现其设计结构的并不太合理。线程池的设计有两个难点。1、在池中线程完成一 个任务后自动阻塞,并等待被唤醒。2、池中的空闲线程数会随着任务的多少而有一个动态的变化,如任务多而空闲线程过少时,程序会创建新的线程来补充;当任务少而空闲线程过多时,程序会取消一些空闲线程以节约系统资源。Linux系统的一个进程最多支持2024个线程。
一些网络服务器在单位时间内需要处理大量的连接请求,但服务的时间去很短。使用普通的方法,即接收一个服务请求,创建一个服务线程方法来提供服务,会浪费系统很多资源。因为线程的创建和销毁己经占用了大量的CPU。而使用线程池方法能够很好的解决这一问题。
线程池采用预创建技术,在应用程序启动后,立即创建一定数量的线程,并让这些线程处于阻塞状态,(即空闲线程)不消耗CPU,只占用较小的内存空间。当任 务来临时,应用程序即唤醒一个空闲的线程,并处理此任务。当此线程处理完任务后,重新回到阻塞状态,并不退出。当系统比较空闲时,大部分线程处于空闲状 态,线程池会自动销毁一些线程,回收系统资源。
下面一个线程池构架。不同于一些网友对线程池的设计,此构架更为简单。程序是根据一网络上现有程序修改的,链接地址:http://cppthreadpool.googlecode.com/svn/trunk/,有兴趣的话可以自己去看源代码,在这里不做过多介绍。
线程池共有两个类,WorkThread 和 ThreadPool。WorkThread 是工作线程类,即线程池中线程所需执行的任务。当有一个新的WorkerThread对象到达时,即有一个处于阻塞状态的线程被唤醒。
class WorkerThread{
public:
int id;
unsigned virtual executeThis()
{
return 0;
}
WorkerThread(int id) : id(id) {}
virtual ~WorkerThread(){}
};
ThreadPool类负责对线程池进行管理,包括:创建新线程、线程间的同步、把新的任务加入到工作队列中、让池中的线程数动态的改变。其类声明如下:
class ThreadPool{
public:
ThreadPool();
ThreadPool(int maxThreadsTemp);
virtual ~ThreadPool();
void destroyPool(int maxPollSecs);
bool assignWork(WorkerThread *worker);
bool fetchWork(WorkerThread **worker);
void initializeThreads();
static void *threadExecute(void *param);
static pthread_mutex_t mutexSync;
static pthread_mutex_t mutexWorkCompletion;
protected:
static void MoveToBusyList(pthread_t id); //move and idle thread to busy thread
static void MoveToIdleList(pthread_t id);
void CreateIdleThread(int num);
void DeleteIdleThread(int num);
pthread_mutex_t m_VarMutex; //mutex for var
pthread_mutex_t mutexThreadList;
static pthread_mutex_t mutexBusyList;
static pthread_mutex_t mutexIdleList;
private:
unsigned int m_InitNum;
unsigned int m_MaxNum;
unsigned int m_AvailLow;
unsigned int m_AvailHigh;
//unsigned int m_AvailNum;
sem_t availableWork;
//sem_t availableThreads;
vector<pthread_t> m_ThreadList; //Thread List
static vector<pthread_t> m_BusyList; //Busy List
static vector<pthread_t> m_IdleList; //Idle List
vector<WorkerThread *> workerQueue;
//int topIndex;
//int bottomIndex;
int incompleteWork; //number of works be done
int queueSize; //the size of workQueue
};
在源程序上进行了适当的修改,使得池中的空闲线程数可以动态的变化。创建一个线程后,立即此线程的ID存入 m_ThreadList 和 m_IdleList 队列中,通过调用fetchWork函数将自己置于阻塞状态。当workerQueue中没有任务等待执行,fetchWork执行sem_wait()即处于阻塞状态。当有新的任务加入到 workerQueue 中,availableWork 信号执行一次 sem_post 操作,唤醒一个空闲线程。线程被唤醒后,其ID号被添加到 m_BusyList队列中,执行完任务后,ID号在 m_BusyList 队列中被删除,再添加到 m_IdleList 队列中。
应用程序所创建的线程总数不能超过m_MaxNum,池中的线程总数不高于m_MaxNum时,空闲线程维持在 m_AvailLow 之上,同样,当空闲线程数高于m_AvailHigh时,程序会自动销毁一些线程,使空闲线程数目维持在一个合理的范围内。
调用的实现方法如下:
int main(int argc, char **argv)
{
ThreadPool* myPool = new ThreadPool(20);
myPool->initializeThreads();
//We will count time elapsed after initializeThreads()
time_t t1=time(NULL);
//Lets start bullying ThreadPool with tonnes of work !!!
for(unsigned int i=0;i<ITERATIONS;i ){
SampleWorkerThread* myThread = new SampleWorkerThread(i);
cout << "myThread[" << myThread->id << "] = [" << myThread << "]" << endl;
myPool->assignWork(myThread);
}
sleep(10);
for(unsigned int i=0;i<ITERATIONS;i ){
SampleWorkerThread* myThread = new SampleWorkerThread(i);
cout << "myThread[" << myThread->id << "] = [" << myThread << "]" << endl;
myPool->assignWork(myThread);
}
sleep(10);
myPool->destroyPool(2);
time_t t2=time(NULL);
cout << t2-t1 << " seconds elapsed\n" << endl;
delete myPool;
return 0;
}
通过这个测试程序,我们可以看到池中的线程数动态的变化。
ThreadPool的实现代码过长,受篇幅限制不便于发表,如有需要可以留言。