muduo源码阅读笔记(7、EventLoopThreadPool)
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、EvevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
与base文件夹下的通用线程池相比,EventLoopThreadPool更加专门化,专为为EventLoopThread而生,专为EventLoop而生,专为One Loop Per Thread而生,专为网络事件驱动而生,专为Muduo而生!
实现
提供的接口:
class EventLoopThreadPool : noncopyable{
public:
typedef std::function<void(EventLoop*)> ThreadInitCallback;
EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg);
~EventLoopThreadPool();
void setThreadNum(int numThreads) { numThreads_ = numThreads; }
void start(const ThreadInitCallback& cb = ThreadInitCallback());
// valid after calling start()
/// round-robin
EventLoop* getNextLoop();
/// with the same hash code, it will always return the same EventLoop
EventLoop* getLoopForHash(size_t hashCode);
std::vector<EventLoop*> getAllLoops();
bool started() const
{ return started_; }
const string& name() const
{ return name_; }
private:
EventLoop* baseLoop_; // 启动EventLoopThreadPool的EventLoop
string name_; // 线程池名
bool started_; // 启动了?
int numThreads_; // EventLoopThread线程的数量
int next_; // 使用round-robin算法做线程的负载均衡,调度到了哪一个线程?
std::vector<std::unique_ptr<EventLoopThread>> threads_; // 线程池本体
std::vector<EventLoop*> loops_; // 每个线程对应的EventLoop
};
结合muduo源码阅读笔记(6、ExevntLoop和Thread)简单画了一下EventLoopThreadPool的架构图:
实现的伪代码:
EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg)
: baseLoop_(baseLoop),
name_(nameArg),
started_(false),
numThreads_(0),
next_(0){
}
EventLoopThreadPool::~EventLoopThreadPool(){
// Don't delete loop, it's stack variable
}
void EventLoopThreadPool::start(const ThreadInitCallback& cb){
assert(!started_);
baseLoop_->assertInLoopThread();
started_ = true;
for (int i = 0; i < numThreads_; ++i){
char buf[name_.size() + 32];
snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i);
EventLoopThread* t = new EventLoopThread(cb, buf);
threads_.push_back(std::unique_ptr<EventLoopThread>(t));
loops_.push_back(t->startLoop()); // 启动线程
}
if (numThreads_ == 0 && cb){
cb(baseLoop_);
}
}
EventLoop* EventLoopThreadPool::getNextLoop(){ // round-robin算法做负载均衡
baseLoop_->assertInLoopThread();
assert(started_);
EventLoop* loop = baseLoop_; // 线程数为0,就让baseLoop返回
if (!loops_.empty()){
// round-robin
loop = loops_[next_];
++next_;
if (implicit_cast<size_t>(next_) >= loops_.size()){
next_ = 0;
}
}
return loop;
}
EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode){ // hash散列做负载均衡
baseLoop_->assertInLoopThread();
EventLoop* loop = baseLoop_;// 线程数为0,就让baseLoop返回
if (!loops_.empty()){
loop = loops_[hashCode % loops_.size()];
}
return loop;
}
std::vector<EventLoop*> EventLoopThreadPool::getAllLoops(){
baseLoop_->assertInLoopThread();
assert(started_);
if (loops_.empty()){
return std::vector<EventLoop*>(1, baseLoop_);
}else{
return loops_;
}
}
细节明细
疑问:
关于EventLoopThreadPool::getNextLoop()
、EventLoopThreadPool::getLoopForHash
的作用?
解答:
小到线程之间,大到服务器集群之间,都需要保证负载均衡,以免大量的连接集中在某一个线程或者某一台机器,导致压力过大,而使连接任务无法有效处理。
本章完结