随笔之如何实现一个线程池

 
一 缘由:
    最近因工作问题,需要实现一个简单的线程池,满足一下要求,
  • 可伸缩,即一旦发现线程不够用,则可以动态增加线程。(至于缩减线程,这个可能难度比较大,暂时不考虑)。
  • 支持超时任务。比如提交一个Task,可以设置5秒后执行,并且可以设置执行一次,还是每隔5秒执行。
基本上就是这两个要求。下面讨论下实现上的问题。
 
二 Windows平台
1 Windows平台实现一个线程池(不使用完成端口),我最初的想法是:
  •  创建比如20个线程,然后这20个线程都WaitForXXXObject,在一个Event上。
  • 添加任务的时候,触发这个Event,为了避免惊群现象(例如只有1个任务的时候,20个线程全起来抢任务,结果其他19个线程白起来了。这样导致系统效率会显著下降。),CreateEvent的时候可以设置下,保证只有一个在等待的线程会启动。
问题:
  • 不太好实现超时任务,这20个线程,该哪一个去做超时检测呢?虽然Wait函数提供了超时机制,但总不可能这20个都去做超时检测吧?
  • 解决办法是,可能需要单独一个线程去定时检查,然后把到期的任务加入到任务队列头,然后触发Event,这样其他线程就能顺利得到任务了。
  • 另外一种方式是这20个线程中有一个做超时检查,然后执行最先到期的任务。这样的问题就是如果该线程执行的任务要是时间过长的话,将导致其他超时任务没法执行。
  • 综合考虑的话,还是用一个单独的线程去检查比较好。
2 Windows平台上使用完成端口
  • 使用完成端口就简单了,线程池中的线程个数将是CPU个数的2倍(这个是推荐值,应该也是绝大多数人的选择了)。
  • Wait的时候,当有事情发生时,内核会自动调度一个线程去执行。而且接连的任务会倾向于使用同一个线程来执行。这样可以减少线程切换的时间。所以,惊群效应由内核保证不会发生了。
  • 解决超时任务的检查,这个也没有更好的办法。只能采取和上面一样的方法了。
三 Linux平台
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一样的方法了
四 一个实际的线程池设计
  • 对用户来说,线程池处理的是任务。所以给线程池添加的应该是任务。那么任务有高,中,低三个优先级。另外,有些任务是需要一直占有线程的,所以还区分persist和非persist两种。设计的时候,分别有高中低三个优先级队列。线程池在挑选任务的时候,先处理高,然后是中低优先级的任务。
  • 当线程池中的线程个数小于任务个数的时候,线程池应该自动增加池中的线程。这个就是自动扩展。当线程池中的线程检测到自己长时间没有工作,并且池中线程数量超过最大设置的数量时候,那么线程应该自动退出。按这种方式就可以实现一个比较好的自动缩减。这样的话,每个线程都需要有一个超时检测,看看自己是不是多余了。
  • 对于定/超时任务,需要给线程池增加一个高优先级,persist的job。这个job自带一个定时任务队列。添加定时任务,其实就是给这个队列添加成员。然后唤醒该线程。这个线程从其中选择一个任务,然后再提交给线程池。(其实就是我们在Windows上的方案)
 
 
 
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值