Linux 通用线程池的实现

本文讨论了Linux线程池的设计难点及优化方法,包括自动阻塞、动态线程数调整等特性,通过引入预创建技术显著提高服务器处理大量连接请求的效率。文章详细介绍了线程池的类结构和工作流程,展示了如何通过源代码实现线程池的高效运行,最终通过测试程序验证了线程池中线程数的动态变化能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用百度搜索一下“Linux线程池”,很出现很多个结果,有的提供的源程序是可以使用的,但仔细分析后,发现其设计结构的并不太合理。线程池的设计有两个难点。1、在池中线程完成一个任务后自动阻塞,并等待被唤醒。2、池中的空闲线程数会随着任务的多少而有一个动态的变化,如任务多而空闲线程过少时,程序会创建新的线程来补充;当任务少而空闲线程过多时,程序会取消一些空闲线程以节约系统资源。Linux系统的一个进程最多支持2024个线程。

<wbr><wbr><wbr>一些网络服务器在单位时间内需要处理大量的连接请求,但服务的时间去很短。使用普通的方法,即接收一个服务请求,创建一个服务线程方法来提供服务,会浪费系统很多资源。因为线程的创建和销毁己经占用了大量的CPU。而使用线程池方法能够很好的解决这一问题。</wbr></wbr></wbr>

<wbr><wbr><wbr>线程池采用预创建技术,在应用程序启动后,立即创建一定数量的线程,并让这些线程处于阻塞状态,(即空闲线程)不消耗CPU,只占用较小的内存空间。当任务来临时,应用程序即唤醒一个空闲的线程,并处理此任务。当此线程处理完任务后,重新回到阻塞状态,并不退出。当系统比较空闲时,大部分线程处于空闲状态,线程池会自动销毁一些线程,回收系统资源。</wbr></wbr></wbr>

<wbr><wbr><wbr>下面一个线程池构架。不同于一些网友对线程池的设计,此构架更为简单。程序是根据一网络上现有程序修改的,链接地址:<a target="_blank" href="http://cppthreadpool.googlecode.com/svn/trunk/">http://cppthreadpool.googlecode.com/svn/trunk/</a>,有兴趣的话可以自己去看源代码,在这里不做过多介绍。</wbr></wbr></wbr>

<wbr><wbr><wbr>线程池共有两个类,WorkThread 和 ThreadPool。WorkThread是工作线程类,即线程池中线程所需执行的任务。当有一个新的WorkerThread对象到达时,即有一个处于阻塞状态的线程被唤醒。</wbr></wbr></wbr>

class WorkerThread{
public:
<wbr><wbr><wbr> intid;</wbr></wbr></wbr>

<wbr><wbr><wbr>unsigned virtual executeThis()</wbr></wbr></wbr>

<wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>return 0;<br><wbr><wbr><wbr> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>WorkerThread(int id) : id(id) {}<br><wbr><wbr><wbr> virtual~WorkerThread(){}<br> };</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>ThreadPool类负责对线程池进行管理,包括:创建新线程、线程间的同步、把新的任务加入到工作队列中、让池中的线程数动态的改变。其类声明如下:</wbr></wbr></wbr>

class ThreadPool{
public:
<wbr><wbr><wbr>ThreadPool();<br><wbr><wbr><wbr>ThreadPool(int maxThreadsTemp);<br><wbr><wbr><wbr> virtual~ThreadPool();</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>void destroyPool(int maxPollSecs);</wbr></wbr></wbr>

<wbr><wbr><wbr>bool assignWork(WorkerThread *worker);<br><wbr><wbr><wbr> boolfetchWork(WorkerThread **worker);</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>void initializeThreads();<br><wbr><br><wbr><wbr><wbr> static void*threadExecute(void *param);</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>static pthread_mutex_t mutexSync;<br><wbr><wbr><wbr> staticpthread_mutex_t mutexWorkCompletion;<br><wbr><wbr><wbr><br> protected:<br><wbr><wbr><wbr> staticvoid<wbr><wbr><wbr>MoveToBusyList(pthread_tid);<wbr><wbr><wbr>//moveand idle thread to busy thread<br><wbr><wbr><wbr> staticvoid<wbr><wbr><wbr>MoveToIdleList(pthread_t id);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>void CreateIdleThread(int num);<br><wbr><wbr><wbr> voidDeleteIdleThread(int num);</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>pthread_mutex_tm_VarMutex;<wbr><wbr><wbr><wbr><wbr><wbr><wbr>//mutex for var</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>pthread_mutex_tmutexThreadList;<wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>static pthread_mutex_t mutexBusyList;<br><wbr><wbr><wbr> staticpthread_mutex_t mutexIdleList;</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

private:
<wbr><wbr><wbr> unsigned intm_InitNum;</wbr></wbr></wbr>

<wbr><wbr><wbr>unsigned int m_MaxNum;<br><wbr><wbr><wbr> unsigned intm_AvailLow;<br><wbr><wbr><wbr> unsigned intm_AvailHigh;<br><wbr><wbr><wbr> //unsignedint m_AvailNum;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>


<wbr><wbr><wbr> sem_tavailableWork;<br><wbr><wbr><wbr> //sem_tavailableThreads;</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>vector&lt;pthread_t&gt;<wbr><wbr>m_ThreadList;<wbr>//ThreadList<wbr><br><wbr><wbr><wbr> staticvector&lt;pthread_t&gt;<wbr><wbr>m_BusyList;<wbr><wbr>//BusyList</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>staticvector&lt;pthread_t&gt;<wbr><wbr>m_IdleList;<wbr><wbr>//IdleList</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>vector&lt;WorkerThread *&gt;workerQueue;</wbr></wbr></wbr>

<wbr><wbr><wbr>//int topIndex;<br><wbr><wbr><wbr> //intbottomIndex;<br><wbr><br><wbr><wbr><wbr><wbr>intincompleteWork;<wbr><wbr><wbr>//number of works be done</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><br><wbr><wbr><wbr> intqueueSize;<wbr><wbr><wbr><wbr>//thesize of workQueue</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

};

<wbr><wbr><wbr></wbr></wbr></wbr>在源程序上进行了适当的修改,使得池中的空闲线程数可以动态的变化。创建一个线程后,立即此线程的ID存入m_ThreadList 和 m_IdleList队列中,通过调用fetchWork函数将自己置于阻塞状态。当workerQueue中没有任务等待执行,fetchWork执行sem_wait()即处于阻塞状态。当有新的任务加入到workerQueue 中,availableWork 信号执行一次 sem_post操作,唤醒一个空闲线程。线程被唤醒后,其ID号被添加到 m_BusyList队列中,执行完任务后,ID号在 m_BusyList队列中被删除,再添加到 m_IdleList 队列中。

<wbr><wbr><wbr>应用程序所创建的线程总数不能超过m_MaxNum,池中的线程总数不高于m_MaxNum时,空闲线程维持在 m_AvailLow之上,同样,当空闲线程数高于m_AvailHigh时,程序会自动销毁一些线程,使空闲线程数目维持在一个合理的范围内。</wbr></wbr></wbr>

<wbr><wbr><wbr>调用的实现方法如下:</wbr></wbr></wbr>

int main(int argc, char **argv)
{

<wbr><wbr><wbr>ThreadPool* myPool = new ThreadPool(20);<br><wbr><wbr><wbr>myPool-&gt;initializeThreads();</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>//We will count time elapsed after initializeThreads()<br><wbr><wbr><wbr> time_tt1=time(NULL);</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>//Lets start bullying ThreadPool with tonnes of work !!!<br><wbr><wbr><wbr> for(unsignedint i=0;i&lt;ITERATIONS;i ){<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>SampleWorkerThread* myThread = new SampleWorkerThread(i);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>cout &lt;&lt; "myThread["&lt;&lt; myThread-&gt;id&lt;&lt; "] = ["&lt;&lt; myThread&lt;&lt; "]"&lt;&lt; endl;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>myPool-&gt;assignWork(myThread);<br><wbr><wbr><wbr> }<br><wbr><br><wbr><wbr><wbr>sleep(10);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>for(unsigned int i=0;i&lt;ITERATIONS;i ){<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>SampleWorkerThread* myThread = new SampleWorkerThread(i);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>cout &lt;&lt; "myThread["&lt;&lt; myThread-&gt;id&lt;&lt; "] = ["&lt;&lt; myThread&lt;&lt; "]"&lt;&lt; endl;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>myPool-&gt;assignWork(myThread);<br><wbr><wbr><wbr> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>sleep(10);<br><wbr><wbr><wbr>myPool-&gt;destroyPool(2);</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr>time_t t2=time(NULL);<br><wbr><wbr><wbr> cout&lt;&lt; t2-t1&lt;&lt; " seconds elapsed\n"&lt;&lt; endl;<br><wbr><wbr><wbr>deletemyPool;<br><wbr><br><wbr><wbr><wbr> return0;<br></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>}

<wbr><wbr><wbr>通过这个测试程序,我们可以看到池中的线程数动态的变化。</wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>ThreadPool的实现代码过长,受篇幅限制不便于发表,如有需要可以留言。</wbr></wbr></wbr>

<wbr><wbr></wbr></wbr>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值