线程池问题本质上也是生产者-消费者问题,生产者向任务队列中添加任务,线程队列中的线程从任务队列中取出任务执行。
Task函数是要执行的任务;
threads_是线程队列,是一个ptr_vector,内部存放线程指针;
queue_是任务队列;
start函数用来启动线程池(创建固定个数的线程);
run函数用来往线程池中的任务队列添加任务;
runInThread函数是线程池中的线程要执行的函数(显然每个线程要重复执行任务,所以函数中肯定有while循环);
take函数:线程池中的线程函数要去任务队列中获取任务;
ThreadPool.h
#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
#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)
{
char id[32];
snprintf(id, sizeof id, "%d", i);
threads_.push_back(new muduo::Thread(
boost::bind(&ThreadPool::runInThread, this), name_+id));
threads_[i].start();
}
}
void ThreadPool::stop()
{
{
MutexLockGuard lock(mutex_);
running_ = false;
cond_.notifyAll();//把running_置为false后再唤醒所有阻塞线程,这样所有线程都可以跳出runInThread函数
}
for_each(threads_.begin(),
threads_.end(),
boost::bind(&muduo::Thread::join, _1));
}
void ThreadPool::run(const Task& task)
{
if (threads_.empty())//线程池如果为空(没有线程可以运行),则直接在调用run函数的线程中执行任务
{
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;
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
}
}
测试
主线程负责往任务队列中添加任务,创建一个含有5个子线程的线程池处理任务。
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()
{
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");
//主线程负责往任务队列中添加任务
pool.start(5);//线程池中有5个子线程
pool.run(print);
pool.run(print);
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)));
}
muduo::CountDownLatch latch(1);
pool.run(boost::bind(&muduo::CountDownLatch::countDown, &latch));//类的成员函数作为任务
latch.wait();
pool.stop();
}