muduo源码阅读笔记(7、EventLoopThreadPool)

muduo源码阅读笔记(7、EventLoopThreadPool)

Muduo源码笔记系列:

muduo源码阅读笔记(0、下载编译muduo)

muduo源码阅读笔记(1、同步日志)

muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)

muduo源码阅读笔记(3、线程和线程池的封装)

muduo源码阅读笔记(4、异步日志)

muduo源码阅读笔记(5、Channel和Poller)

muduo源码阅读笔记(6、EvevntLoop和Thread)

muduo源码阅读笔记(7、EventLoopThreadPool)

muduo源码阅读笔记(8、定时器TimerQueue)

muduo源码阅读笔记(9、TcpServer)

muduo源码阅读笔记(10、TcpConnection)

muduo源码阅读笔记(11、TcpClient)

前言

与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的架构图:

muduo源码阅读笔记(7、EventLoopThreadPool)_第1张图片

实现的伪代码:

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的作用?

解答:

小到线程之间,大到服务器集群之间,都需要保证负载均衡,以免大量的连接集中在某一个线程或者某一台机器,导致压力过大,而使连接任务无法有效处理。


本章完结

你可能感兴趣的:(Muduo源码阅读笔记,笔记,c++,网络,linux,架构,后端,服务器)