【muduo】线程池

来源:互联网 发布:看书哪个软件好 编辑:程序博客网 时间:2024/05/21 10:39

ThreadPool.h

// Use of this source code is governed by a BSD-style license// that can be found in the License file.//// Author: Shuo Chen (chenshuo at chenshuo dot com)#ifndef MUDUO_BASE_THREADPOOL_H#define MUDUO_BASE_THREADPOOL_H#include <muduo/base/Condition.h>#include <muduo/base/Mutex.h>#include <muduo/base/Thread.h>#include <muduo/base/Types.h>#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/ptr_container/ptr_vector.hpp>#include <deque>namespace muduo{class ThreadPool : boost::noncopyable{ public:  typedef boost::function<void ()> Task;  explicit ThreadPool(const string& nameArg = string("ThreadPool"));  ~ThreadPool();  // Must be called before start().  // 设置线程池任务队列的最大长度  void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; }  //设置线程池的初始化回调函数  void setThreadInitCallback(const Task& cb)  { threadInitCallback_ = cb; }  // 启动线程池,并创建指定数目的线程  void start(int numThreads);  // 停止线程池  void stop();  // 获取线程池名称  const string& name() const  { return name_; }  // 获取任务队列中任务数目  size_t queueSize() const;  // Could block if maxQueueSize > 0  // 运行一个任务,将任务放到任务队列中  void run(const Task& f);#ifdef __GXX_EXPERIMENTAL_CXX0X__  void run(Task&& f);#endif private:  // 任务队列是否已满  bool isFull() const;  // 线程处理函数,这个函数用来取出线程池任务队列中的任务,然后进行处理  void runInThread();  // 从任务队列中取出任务  Task take();  // 互斥量,用户保护任务队列,和下面两个条件变量  mutable MutexLock mutex_;  // 条件变量,任务队列不空,可以取任务  Condition notEmpty_;  // 条件变量,任务队列不满,可以添加任务  Condition notFull_;  // 线程池名称  string name_;  //初始化线程时所用回调函数  Task threadInitCallback_;  // 线程列表 ptr_vector是boost库的指针容器  boost::ptr_vector<muduo::Thread> threads_;  // 任务队列  std::deque<Task> queue_;  // 任务队列的最大数值  size_t maxQueueSize_;  // 线程池是否正在运行  bool running_;};}#endif

ThreadPool.cpp

// Use of this source code is governed by a BSD-style license// that can be found in the License file.//// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/base/ThreadPool.h>#include <muduo/base/Exception.h>#include <boost/bind.hpp>#include <assert.h>#include <stdio.h>using namespace muduo;ThreadPool::ThreadPool(const string& nameArg)  : mutex_(),    notEmpty_(mutex_),    notFull_(mutex_),    name_(nameArg),    maxQueueSize_(0),    running_(false){}ThreadPool::~ThreadPool(){  if (running_)  {    stop();  }}// 启动线程池,线程池中创建指定数目的线程void ThreadPool::start(int numThreads){  assert(threads_.empty());  running_ = true;  threads_.reserve(numThreads);  for (int i = 0; i < numThreads; ++i)  {    char id[32];    snprintf(id, sizeof id, "%d", i+1);    //创建线程并启动    threads_.push_back(new muduo::Thread(          boost::bind(&ThreadPool::runInThread, this), name_+id));    threads_[i].start();  }  // 如果要求创建线程的数目为0,并且设定了线程池初始化回调函数,就调用线程池初始化回调函数  if (numThreads == 0 && threadInitCallback_)  {    threadInitCallback_();  }}// 停止线程池void ThreadPool::stop(){  {  MutexLockGuard lock(mutex_);  running_ = false;  notEmpty_.notifyAll();  }  // 阻塞并等待所有线程执行完毕  for_each(threads_.begin(),           threads_.end(),           boost::bind(&muduo::Thread::join, _1));}// 获取线程池任务队列数目size_t ThreadPool::queueSize() const{  MutexLockGuard lock(mutex_);  return queue_.size();}// 处理任务void ThreadPool::run(const Task& task){  if (threads_.empty())  {    //如果线程池中没有处理线程,就直接执行任务,注意并没有重新开始一个新的线程,所以是以阻塞方式进行    task();  }  else  {    // 否则,就等待任务队列不满的情况下,将任务加入任务队列,并通知线程任务队列已经非空    MutexLockGuard lock(mutex_);    while (isFull())    {      notFull_.wait();    }    assert(!isFull());    queue_.push_back(task);    notEmpty_.notify();  }}// C++11 的右值引用版本#ifdef __GXX_EXPERIMENTAL_CXX0X__void ThreadPool::run(Task&& task){  if (threads_.empty())  {    task();  }  else  {    MutexLockGuard lock(mutex_);    while (isFull())    {      notFull_.wait();    }    assert(!isFull());    queue_.push_back(std::move(task));    notEmpty_.notify();  }}#endif// 从任务对垒中取出一个任务ThreadPool::Task ThreadPool::take(){  MutexLockGuard lock(mutex_);  // always use a while-loop, due to spurious wakeup  // 等待任务队列非空  while (queue_.empty() && running_)  {    notEmpty_.wait();  }  // 取出任务队列  Task task;  if (!queue_.empty())  {    task = queue_.front();    queue_.pop_front();    // 通知其他线程,任务队列不满    if (maxQueueSize_ > 0)    {      notFull_.notify();    }  }  return task;}// 判断任务队列是否已满bool ThreadPool::isFull() const{  mutex_.assertLocked();  return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_;}// 这个就是线程处理函数,主要功能就是开始一个循环,然后从任务队列中取出任务,并执行任务void ThreadPool::runInThread(){  try  {    if (threadInitCallback_)    {      threadInitCallback_();    }    while (running_)    {      Task task(take());      if (task)      {        task();      }    }  }  catch (const Exception& ex)  {    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());    fprintf(stderr, "reason: %s\n", ex.what());    fprintf(stderr, "stack trace: %s\n", ex.stackTrace());    abort();  }  catch (const std::exception& ex)  {    fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());    fprintf(stderr, "reason: %s\n", ex.what());    abort();  }  catch (...)  {    fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str());    throw; // rethrow  }}

注意点:

线程池的创建和任务处理,用到了生产者消费者模型。
任务队列中新加任务是生产者进行生产,线程池中处理线程处理任务是消费者进行消费。注意任务队列的同步。

原创粉丝点击