本篇博客针对EventLoopThread类和EventLoopThreadPool类做下小结。
博客代码来自于陈硕的muduo网络库,github地址https://github.com/chenshuo/muduo
学习笔记:
EventLoopThread类又叫IO线程类,专门用来处理IO事件。在它的线程函数里会创建一个EventLoop对象,执行loop循环处理IO事件。这个EventLoop对象会传递出去供外部对象使用,比如外部创建的socket、定时器会把他们的读写操作放到该loop循环中执行。而且多个socket、定时器的读写操作可以放到同一个loop循环中。
EventLoopThreadPool类又叫IO线程池类,由1个主线程+N个子线程组成,“1+N”的模式一般用在服务端,主线程用于接收所有客户端的连接请求,各子线程用于处理多个客户端的IO事件。给线程池分配客户端的时候采取循环分配的方式,保证线程池的负载平衡。多个客户端的IO操作可以对应于1个IO线程,但是1个客户端的IO操作不能对应于多个IO线程,因为多个IO线程抢占执行同一个客户端的读写操作会因为可能导致串写而需要用互斥锁。
EventLoopThread作为EventLoopThreadPool的成员对象,多个EventLoopThread对象保存到std::vector中构成了EventLoopThreadPool的线程池。
EventLoopThread.h
#ifndef MUDUO_NET_EVENTLOOPTHREAD_H
#define MUDUO_NET_EVENTLOOPTHREAD_H
#include "muduo/base/Condition.h"
#include "muduo/base/Mutex.h"
#include "muduo/base/Thread.h"
namespace muduo
{
namespace net
{
class EventLoop;
class EventLoopThread : noncopyable
{
public:
typedef std::function<void(EventLoop*)> ThreadInitCallback;
EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(),
const string& name = string());
~EventLoopThread();
//开启当前IO线程,在线程中创建loop_并返回其指针供外部使用
EventLoop* startLoop();
private:
//线程入口函数,loop_的生命周期与此相同
void threadFunc();
EventLoop* loop_ GUARDED_BY(mutex_);//loop循环执行外部传进来的IO操作
bool exiting_;//退出循环标志
Thread thread_;//线程对象
MutexLock mutex_;
Condition cond_ GUARDED_BY(mutex_);
ThreadInitCallback callback_;//线程初始化回调,可有可无
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_EVENTLOOPTHREAD_H
EventLoopThread.cpp
#include "muduo/net/EventLoopThread.h"
#include "muduo/net/EventLoop.h"
using namespace muduo;
using namespace muduo::net;
EventLoopThread::EventLoopThread(const ThreadInitCallback& cb,
const string& name)
: loop_(NULL),
exiting_(false),
thread_(std::bind(&EventLoopThread::threadFunc, this), name),
mutex_(),
cond_(mutex_),
callback_(cb)
{
}
EventLoopThread::~EventLoopThread()
{
exiting_ = true;
if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_.
{
// still a tiny chance to call destructed object, if threadFunc exits just now.
// but when EventLoopThread destructs, usually programming is exiting anyway.
loop_->quit();
thread_.join();
}
}
EventLoop* EventLoopThread::startLoop()
{
assert(!thread_.started());
thread_.start();
//条件变量等待线程启动,然后返回loop
EventLoop* loop = NULL;
{
MutexLockGuard lock(mutex_);
while (loop_ == NULL)
{ //等待threadFunc()的唤醒
cond_.wait();
}
loop = loop_;
}
//loop传出去后用户可以往loop里加入IO操作
return loop;
}
void EventLoopThread::threadFunc()
{
/*在线程里创建EventLoop对象,执行loop循环,这样线程就变成了一个IO线程
loop的生命周期与线程入口函数同生共死*/
EventLoop loop;
//如果用户注册了初始化回调就执行
if (callback_)
{
callback_(&loop);
}
{//锁的生命周期及作用范围仅限于这对大括号内
MutexLockGuard lock(mutex_);
loop_ = &loop;
cond_.notify();//唤醒startLoop()的条件等待
}
//IO线程在此执行所有的IO操作
loop.loop();
//assert(exiting_);
MutexLockGuard lock(mutex_);
loop_ = NULL;
}
EventLoopThreadPool.h
#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H
#define MUDUO_NET_EVENTLOOPTHREADPOOL_H
#include "muduo/base/noncopyable.h"
#include "muduo/base/Types.h"
#include <functional>
#include <memory>
#include <vector>
namespace muduo
{
namespace net
{
class EventLoop;
class EventLoopThread;
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
//循环获取下一个线程池的loop
EventLoop* getNextLoop();
/// with the same hash code, it will always return the same EventLoop
EventLoop* getLoopForHash(size_t hashCode);
//获取所有loop
std::vector<EventLoop*> getAllLoops();
bool started() const
{ return started_; }
const string& name() const
{ return name_; }
private:
//线程池类用于服务端,baseLoop_用于接收新连接,线程池用于处理这些新连接的IO操作
EventLoop* baseLoop_;
string name_;
bool started_;//开始标志
int numThreads_;//IO线程池的线程个数
int next_;//下一个IO线程的相关索引
std::vector<std::unique_ptr<EventLoopThread>> threads_;//保存线程池的线程对象指针
std::vector<EventLoop*> loops_;//保存线程池的loop指针
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H
EventLoopThreadPool.cpp
#include "muduo/net/EventLoopThreadPool.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/EventLoopThread.h"
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
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;
//依次开启线程池中的IO线程
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());
}
//如果线程池的数量是0,则所有外部IO操作均有baseLoop_完成
if (numThreads_ == 0 && cb)
{
cb(baseLoop_);
}
}
//循环获取下一个线程池的loop,保证各IO线程上执行的IO操作基本负载均衡
EventLoop* EventLoopThreadPool::getNextLoop()
{
baseLoop_->assertInLoopThread();
assert(started_);
EventLoop* loop = 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)
{
baseLoop_->assertInLoopThread();
EventLoop* loop = 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_;
}
}