一、线程池简介
线程池本质上也是生产者消费者问题:生产者线程向任务队列添加任务,消费者线程(在线程队列中)从任务队列取出任务去执行。
二、ThreadPool源码
#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 <deque>
#include <vector>
namespace muduo
{
class ThreadPool : noncopyable
{
public:
// 定义function类模板
typedef std::function<void ()> Task;
explicit ThreadPool(const string& nameArg = string("ThreadPool"));
~ThreadPool();
// 设置线程池中线程的最大数目
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;
void run(Task f);
private:
bool isFull() const REQUIRES(mutex_); // 判断是否满
void runInThread(); // 线程池的线程运行函数
Task take(); // 取任务函数(返回类型是一个function)
mutable MutexLock mutex_; // mutable表示在const函数也可以改变它
Condition notEmpty_ GUARDED_BY(mutex_); //任务队列queue_不为空,说明可以向任务队列取任务了
Condition notFull_ GUARDED_BY(mutex_); //任务队列queue_不满了,说明可以向任务队列添加任务
string name_;
Task threadInitCallback_; // 线程初始化回调函数
std::vector<std::unique_ptr<muduo::Thread>> threads_; // 线程组
std::deque<Task> queue_ GUARDED_BY(mutex_); // 任务队列
size_t maxQueueSize_; // 最大任务数
bool running_; // 线程池运行状态
};
} // namespace muduo
#endif // MUDUO_BASE_THREADPOOL_H
#include <muduo/base/ThreadPool.h>
#include <muduo/base/Exception.h>
#include <assert.h>
#include <stdio.h>
using namespace muduo;
ThreadPool::ThreadPool(const string& nameArg)
: mutex_(),
notEmpty_(mutex_), // 初始化的时候需要把condition和mutex关联起来
notFull_(mutex_),
name_(nameArg),
maxQueueSize_(0),
running_(false)
{
}
ThreadPool::~ThreadPool()
{
if (running_)
{
stop();
}
}
/********************************************************************
Description : 启动线程池。
*********************************************************************/
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);
// 创建线程并存放线程指针,绑定的函数为runInThread
threads_.emplace_back(new muduo::Thread(std::bind(&ThreadPool::runInThread, this), name_+id));
// 启动线程,即runInThread函数执行
threads_[i]->start();
}
// 如果线程池线程数为0,且设置了回调函数
if (numThreads == 0 && threadInitCallback_)
{
threadInitCallback_(); // 本线程自己执行init回调函数
}
}
/********************************************************************
Description : 终止线程池。
*********************************************************************/
void ThreadPool::stop()
{
{
MutexLockGuard lock(mutex_);
running_ = false;
// 不管当前线程在执行什么任务,通知所有线程去notEmpty_.wait()处等待
// 因为running_为false,所有线程不会再执行任何任务了。
notEmpty_.notifyAll();
}
// 回收所有线程
for (auto& thr : threads_)
{
thr->join();
}
}
// 获取任务队列的大小
size_t ThreadPool::queueSize() const
{
MutexLockGuard lock(mutex_);
return queue_.size();
}
/********************************************************************
Description : 向任务队列中添加任务。
*********************************************************************/
void ThreadPool::run(Task task)
{
if (threads_.empty())
{
task(); // 如果没有子线程,就在主线程中直接执行该task
}
else
{
MutexLockGuard lock(mutex_);
while (isFull())
{
notFull_.wait(); // 等待任务队列不为满的条件
}
assert(!isFull());
// 如果任务队列不满,则可以向任务队列中添加任务
queue_.push_back(std::move(task));
notEmpty_.notify(); // 唤醒等待任务队列不为空的线程来取任务
}
}
/********************************************************************
Description : 向任务队列中取任务,take函数是每个线程都执行的。
*********************************************************************/
ThreadPool::Task ThreadPool::take()
{
MutexLockGuard lock(mutex_);
// 避免虚假唤醒
// 如果任务队列为空,并且线程池处于运行态
while (queue_.empty() && running_)
{
notEmpty_.wait(); // 等待任务队列不为空的条件
}
Task task; // 定义任务变量,Task是一个函数类型
if (!queue_.empty()) // 任务队列不为空
{
task = queue_.front(); // 取队列头获取一个任务并初始化task
queue_.pop_front();
if (maxQueueSize_ > 0)
{
// 取了一个任务之后,唤醒等待任务队列不为满的线程来添加任务
notFull_.notify();
}
}
return task;
}
// 判断任务队列是否满
bool ThreadPool::isFull() const
{
mutex_.assertLocked();
return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_;
}
/********************************************************************
Description : 取任务并执行。
*********************************************************************/
void ThreadPool::runInThread()
{
try
{
if (threadInitCallback_)
{
threadInitCallback_();
}
while (running_) // 当线程池启动之后,就在while循环中不停地取任务执行
{
Task task(take()); // 取任务并初始化task,无任务会阻塞
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
}
}