1. 程式人生 > >muduo網路庫原始碼學習————執行緒池實現

muduo網路庫原始碼學習————執行緒池實現

muduo庫裡面的執行緒池是固定執行緒池,即建立的執行緒池裡面的執行緒個數是一定的,不是動態的。執行緒池裡面一般要包含執行緒佇列還有任務佇列,外部程式將任務存放到執行緒池的任務佇列中,執行緒池中的執行緒佇列執行任務,也是一種生產者和消費者模型。muduo庫中的執行緒池原始碼如下:
執行緒池標頭檔案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& name = string()); ~ThreadPool(); //啟動執行緒池 void start(int numThreads); //關閉執行緒池 void stop(); //執行任務,往執行緒池當中的任務佇列新增任務
void run(const Task& f); private: //執行緒池當中的執行緒要執行的函式 void runInThread(); //獲取任務 Task take(); MutexLock mutex_;//和條件變數配合使用的互斥鎖 Condition cond_;//條件變數用來喚醒執行緒池中的執行緒佇列來執行任務 string name_;//執行緒池名稱 boost::ptr_vector<muduo::Thread> threads_;//存放執行緒指標 std::deque<Task> queue_;//任務佇列 bool running_;//執行緒池是否處於執行的狀態 }; } #endif

執行緒池實現檔案ThreadPool.cc

// 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& name) : mutex_(),cond_(mutex_), name_(name),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)
  {//for迴圈建立執行緒
    char id[32];
    //執行緒號
    snprintf(id, sizeof id, "%d", i);
    //建立執行緒並存放執行緒指標,繫結的函式為runInThread
    threads_.push_back(new muduo::Thread(boost::bind(&ThreadPool::runInThread, this), name_+id));
    threads_[i].start();//啟動執行緒,即runInThread函式執行
  }
}
//關閉執行緒池
void ThreadPool::stop()
{
  {
  MutexLockGuard lock(mutex_);
  running_ = false;//running置為false
  cond_.notifyAll();//通知所有執行緒
  }
//等待執行緒退出
  for_each(threads_.begin(),threads_.end(),boost::bind(&muduo::Thread::join, _1));
}
//新增任務
void ThreadPool::run(const Task& task)
{//將任務新增到執行緒池當中的任務佇列
  if (threads_.empty())//如果執行緒池當中的執行緒是空的
  {
    task();//直接執行任務
  }
  else//否則新增
  {
    MutexLockGuard lock(mutex_);
    queue_.push_back(task);
    cond_.notify();//通知隊列當中有任務了
  }
}
//獲取任務函式
ThreadPool::Task ThreadPool::take()
{//加鎖保護
  MutexLockGuard lock(mutex_);
  // always use a while-loop, due to spurious wakeup
  //如果佇列為空並且處於執行的狀態
  while (queue_.empty() && running_)
  {
    cond_.wait();//等待
  }
  Task task;//定義任務變數,Task是一個函式型別
  if(!queue_.empty())//有任務到來
  {
    task = queue_.front();//取出任務
    queue_.pop_front();//彈出任務
  }
  return task;//返回任務
}

void ThreadPool::runInThread()
{
  try//可能發生異常
  {
    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
  }
}

下面是測試程式碼:
ThreadPool_test.cc

//執行緒池測試程式碼
#include <muduo/base/ThreadPool.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/base/CurrentThread.h>

#include <boost/bind.hpp>
#include <stdio.h>

void print()
{//簡單地列印tid
  printf("tid=%d\n", muduo::CurrentThread::tid());
}

void printString(const std::string& str)
{
  printf("tid=%d, str=%s\n", muduo::CurrentThread::tid(), str.c_str());
}

int main()
{//建立一個執行緒池
  muduo::ThreadPool pool("MainThreadPool");
  //5個執行緒的執行緒池
  pool.start(5);
  //添加了2個任務執行print
  pool.run(print);
  pool.run(print);
  //添加了100個任務
  for (int i = 0; i < 100; ++i)
  {
    char buf[32];
    snprintf(buf, sizeof buf, "task %d", i);
    //繫結的函式是帶引數的
    pool.run(boost::bind(printString, std::string(buf)));
  }
  //建立CountDownLatch物件,計數值count =1,只需執行一個countDown
  muduo::CountDownLatch latch(1);
  //新增一個任務
  pool.run(boost::bind(&muduo::CountDownLatch::countDown, &latch));
  //count不為0的時候一直等待
  latch.wait();
  //關閉執行緒池
  pool.stop();
}

執行結果如下:
這裡寫圖片描述