zoukankan      html  css  js  c++  java
  • 并发编程(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

  • 相关阅读:
    关于sqlserver2008 bcp根据数据表导出xml格式文件的小记
    关于SQL SERVER 2008 X64版本报错:消息 7302,级别 16,无法创建链接服务器 "(null)" 的 OLE DB 访问接口 "Microsoft.ACE.OLEDB.12.0" 的实例。
    Response.Redirect(),Server.Transfer(),Server.Execute()的区别[转]
    ASP.net应用程序中如何调用客户端的Javascript脚本小结(转)
    重写ListView控件,实现点击列头排序的功能
    关于Response.redirect和Response.End出现线程中止异常的处理(转)
    持续集成cruisecontrol.net学习总结
    [转]关于PowerDesigner反向工程SQL Server2000数据库时生成注释的解决方法
    敏捷开发scrum学习笔记一
    asp.net缓存机制总结(转)
  • 原文地址:https://www.cnblogs.com/huangfuyuan/p/9134544.html
Copyright © 2011-2022 走看看