ThreadPool
1 Linux平台实现线程池
基本思路和Windows一样,但是由于Linux提供的线程同步原语(POSIX)不如Windows好用,导致有一些特殊的地方需要注意:
>在Windows上,线程间通知无外乎就是使用Event,在Linux上,使用POSIX的condition+mutex,也能完成同样的操作,但是这种方式在linux中用得相对较少,而是大量使用pipe,创建两个fd。当线程1想唤醒线程2的时候,就可以往writeFD中写数据,这样线程2阻塞在readFD中就能返回。我之前及其没搞明白为何要使用pipe,后来突然想明白了。因为Linux上阻塞的方法就是用select,poll和epoll,其中等待的都是FD,那么采用FD这种方式,能够统一调用方法。(因为POSIX缺乏WaitForMultiObject导致,网上有一个Linux下Wait/CreateEvent的系列实现,很难下载到。呵呵)
>但是,现在有20个线程,总不可能创建20个pipe吧?即使有20个pipe,那么我要唤醒哪个线程,就得单独往那个线程的writeFD写数据。这明显不是一个好办法。只能使用condition+mutex了。为了避免惊群,操作cond的时候,只能使用Signal,而非Broadcast
>超时任务的处理,那么也只能和Windows一样的方法了
2 一个实际的线程池设计
>对用户来说,线程池处理的是任务。所以给线程池添加的应该是任务。那么任务有高,中,低三个优先级。另外,有些任务是需要一直占有线程的,所以还区分persist和非persist两种。设计的时候,分别有高中低三个优先级队列。线程池在挑选任务的时候,先处理高,然后是中低优先级的任务。
>当线程池中的线程个数小于任务个数的时候,线程池应该自动增加池中的线程。这个就是自动扩展。当线程池中的线程检测到自己长时间没有工作,并且池中线程数量超过最大设置的数量时候,那么线程应该自动退出。按这种方式就可以实现一个比较好的自动缩减。这样的话,每个线程都需要有一个超时检测,看看自己是不是多余了。
>对于定/超时任务,需要给线程池增加一个高优先级,persist的job。这个job自带一个定时任务队列。添加定时任务,其实就是给这个队列添加成员。然后唤醒该线程。这个线程从其中选择一个任务,然后再提交给线程池。(其实就是我们在Windows上的方案)
--------------------------------------------------------------------------------------------
一个线程池的实现
Ø 提供一个线程池的组件,具有良好的伸缩性,当线程够用时,销毁不用线程,当线程不够用时,自动增加线程数量;
Ø 提供一个工作任务接口和工作队列,实际所需要的任务都必须实现这个工作任务接口,然后放入工作队列中;
Ø 线程池中的线程从工作队列中,自动取得工作任务,执行任务。
主要控制类和功能接口设计
线程池管理器 ThreadPoolManager 的功能:
Ø 管理线程池中的各个属性变量
ü 最大工作线程数
ü 最小工作线程数
ü 激活的工作线程总数
ü 睡眠的工作线程总数
ü 工作线程总数 (即:激活的工作线程总数+睡眠的工作线程总数)
Ø 创建工作线程
Ø 销毁工作线程
Ø 启动处于睡眠的工作线程
Ø 睡眠处于激活的工作线程
Ø 缩任务:当工作线程总数小于或等于最小工作线程数时,销毁多余的睡眠的工作线程,使得现有工作线程总数等于最小工作任务总数
Ø 伸任务:当任务队列任务总数大于工作线程数时,增加工作线程总数至最大工作线程数
Ø 提供线程池启动接口
Ø 提供线程池销毁接口
工作线程 WorkThread 的功能:
Ø 从工作队列取得工作任务
Ø 执行工作任务接口中的指定任务
工作任务接口 ITask 的功能:
Ø 提供指定任务动作
工作队列 IWorkQueue 的功能:
Ø 提供获取任务接口,并删除工作队列中的任务;
Ø 提供加入任务接口;
Ø 提供删除任务接口;
Ø 提供取得任务总数接口;
Ø 提供自动填任务接口;(当任务总数少于或等于默认总数的25%时,自动装填)
Ø 提供删除所有任务接口;

浙公网安备 33010602011771号