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
}
}
注意点:
线程池的创建和任务处理,用到了生产者消费者模型。
任务队列中新加任务是生产者进行生产,线程池中处理线程处理任务是消费者进行消费。注意任务队列的同步。