1 线程池原理
muduo源码中线程池的实现是基于生产者/消费者模式的,可参考基于生产者/消费者模式原理实现无界缓冲区和有界缓冲区。其中缓冲区(即下图中的任务队列)为“环形缓冲区”。
其实现原理如下:
2 代码实现
2.1 类图
2.2 代码
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 <deque>
#include <vector>
namespace muduo
{
class ThreadPool : noncopyable
{
public:
typedef std::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; }
// 启动线程池 numThreads:启动的初始线程个数
// 完成线程池的初始化
void start(int numThreads);
// 关闭线程池
void stop();
const string& name() const
{ return name_; }
size_t queueSize() const;
// Could block if maxQueueSize > 0
// Call after stop() will return immediately.
// There is no move-only version of std::function in C++ as of C++14.
// So we don't need to overload a const& and an && versions
// as we do in (Bounded)BlockingQueue.
// https://stackoverflow.com/a/25408989
// 向任务队列中添加任务Task f 生产者
void run(Task f);
private:
bool isFull() const REQUIRES(mutex_);
void runInThread();// 调用take()函数实现从线程池中取任务
Task take();// 去线程池中取任务 消费者
mutable MutexLock mutex_;
Condition notEmpty_ GUARDED_BY(mutex_);
Condition notFull_ GUARDED_BY(mutex_);
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
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 <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
running_ = true;
// 为threads_线程队列预置空间
threads_.reserve(numThreads);
for (int i = 0; i < numThreads; ++i)
{
char id[32];
snprintf(id, sizeof id, "%d", i+1);
// 创建线程(muduo::Thread类的一个对象)并添加到线程队列中
// 创建的线程绑定的函数为runInThread()
threads_.emplace_back(new muduo::Thread(
std::bind(&ThreadPool::runInThread, this), name_+id));// name_+id 线程名称
// 启动线程
// muduo::Thread类的start()函数负责创建线程
threads_[i]->start();
}
if (numThreads == 0 && threadInitCallback_)
{
threadInitCallback_();
}
}
void ThreadPool::stop()
{
{
MutexLockGuard lock(mutex_);
// 将running_置为false
running_ = false;
notEmpty_.notifyAll();
notFull_.notifyAll();
}
for (auto& thr : threads_)
{
thr->join();// 等待线程的退出
}
}
size_t ThreadPool::queueSize() const
{
MutexLockGuard lock(mutex_);
return queue_.size();
}
void ThreadPool::run(Task task)
{
// 如果当前线程队列中没有线程(当前没有消费者) 则由ThreadPool直接代为执行该任务
if (threads_.empty())
{
task();
}
else
{
MutexLockGuard lock(mutex_);
while (isFull() && running_)
{
notFull_.wait();
}
if (!running_) return;
assert(!isFull());
// 添加任务task到任务队列
queue_.push_back(std::move(task));
notEmpty_.notify();
}
}
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();// 任务队列pop()
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_)
{
// 获取任务
// runInThread()函数调用take()函数 take()返回任务队列中的任务函数--一个函数指针/地址
Task task(take());// take()处于阻塞状态 等待任务队列不为空
if (task)
{
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
}
}
3 参考源码
测试代码参见源码的$MUDUO_HOME/muduo/base/tests/路径下的ThreadPool_test.cc文件。
源码地址:https://github.com/GaoZiqiang/gmuduo