并发编程(9)线程池---高级线程管理

       我们通过创建 std::thread 对象来对线程进行管理。在一些情况下,这种方式不可行,因为需要在线程的整个生命周期中对其进行管理,并根据硬件来确定线程数量,等等。另一种情况是,当使用多线程来解决某个问题时,在某个条件达成的时候,可以提前结束。

       所以从管理线程任务的机制,两个角度介绍线程池。

一、简单的线程池

  定义:管理一个任务队列,一个线程队列,然后每次取一个任务分配给一个线程去做,循环往复。作为最简单的线程池,其拥有固定数量的工作线程(通常工作线程数量std::thread::hardware_concurrency() 相同)。当工作需要完成时,可以调用函数将任务挂在任务队列中。每个工作线程都会从任务队列上获取任务,然后执行这个任务,执行完成后再回来获取新的任务。

      简单的线程池:

class thread_pool
{
  std::atomic_bool done;
  thread_safe_queue<std::function<void()> > work_queue; // 1   线程安全队列管理任务队列
  std::vector<std::thread> threads; // 2   工作线程
  join_threads joiner; // 3  来汇聚所有线程
  void worker_thread()
  {
    while(!done) // 4
    {
      std::function<void()> task;
      if(work_queue.try_pop(task)) // 5  从队列上获取任务
      {
        task(); // 6  执行任务,可在此加上线程数目增加语句。完成任务,增加一个空闲线程数目
      }
      else
      {
        std::this_thread::yield(); // 7  让线程休息
      }
    }
  }
public:
  thread_pool():  //列表初始化类
  done(false),joiner(threads)
  {
    unsigned const
    thread_count=std::thread::hardware_concurrency(); // 8 获取硬件支持并发数
    try
    {
      for(unsigned i=0;i<thread_count;++i)
      {
        threads.push_back(
        std::thread(&thread_pool::worker_thread,this)); // 9   线程执行于此,每个线程都会执行获取任务的函数。但是,本简单线程池不支持线程的回收循环利用
      }                                                   //可以,在回收线程那里加上--thread_count;从而可以多次循环
    }
    catch(...)
    {
      done=true; // 10
       throw;
    }
  }
  ~thread_pool()
  {
    done=true; // 11
  }
  template<typename FunctionType>
  void submit(FunctionType f)
  {
    work_queue.push(std::function<void()>(f)); // 12  将函数f包装成一个std::function<void()>实例,推入队列之中
  }
};

CPU密集型的程序要(cpu个数个+1)个线程就行了,I/O密集型,因为I/O操作不需要访问CPU,所以可以创建多个线程(2*NUM_cpu).

另一个思路,先创建一定量的线程,当忙碌线程达到总线程的80%时,创建新的线程。

总之线程池通常适合下面的几个场合: 
(1) 单位时间内处理任务频繁而且任务处理时间短 
(2) 对实时性要求较高。如果接受到任务后在创建线程,可能满足不了实时要求,因此必须采用线程池进行预创建。 
(3) 必须经常面对高突发性事件,比如Web服务器,如果有足球转播,则服务器将产生巨大的冲击。此时如果采取传统方法,则必须不停的大量产生线程,销毁线程。此时采用动态线程池可以避免这种情况的发生。

以后填坑@@//TODO

原文地址:https://www.cnblogs.com/huangfuyuan/p/9134544.html