muduo源码分析之EventLoopThreadPool
相关文件
//IO线程池
muduo/net/EventLoopThreadPool.h
muduo/net/EventLoopThreadPool.cc
//IO线程类
muduo/net/EventLoopThread.h
muduo/net/EventLoopTHread.cc
作用
EventLoopThread IO线程类会启动自己的线程,并在其中运行EventLoop::loop()。
EventLoopThreadPool IO线程池是TCPserver的一个成员,功能式开启若干个IO线程,并让这些IO线程处于事件循环的状态。
在muduo中,使用one loop per thread的思想实现多线程TcpServer。关键步骤是在建立新连接TcpConnection时,从IO线程池中挑选一个loop构造TcpConnection。
多线程TcpServer自己的EventLoop只用来接受新连接,而
新连接会用其他EventLoop来执行IO。
图中,每个Reacctor都属于一个线程,mainReactor关注的是acceptor,即监听套接字listenfd相关的事件。subReactor关注的是已连接套接字connfd相关的事件。
使用
TcpServer类中包含一个
std::shared_ptr<EventLoopThreadPool> threadPool_;
数据成员,在构造函数中初始化。
建立新连接时,调用threadPool_->getNextLoop()从IO线程池取一个EventLoop构造TcpConnection。
//TcpServer.cc
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
loop_->assertInLoopThread();
EventLoop* ioLoop = threadPool_->getNextLoop();//!!取一个loop
char buf[64];
snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);
++nextConnId_;
string connName = name_ + buf;
LOG_INFO << "TcpServer::newConnection [" << name_
<< "] - new connection [" << connName
<< "] from " << peerAddr.toIpPort();
InetAddress localAddr(sockets::getLocalAddr(sockfd));
// FIXME poll with zero timeout to double confirm the new connection
// FIXME use make_shared if necessary
//!!用ioloop构造新连接
TcpConnectionPtr conn(new TcpConnection(ioLoop,
connName,
sockfd,
localAddr,
peerAddr));
connections_[connName] = conn;
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
//!!在ioloop中执行TcpConnection的回调函数
ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));
}
EventLoopThread源码分析
EventLoopThread类
对外接口函数只有startLoop(),用于开启事件循环。
在构造EventLoopThread类时,注册线程函数threadFunc()。
//类声明
class EventLoopThread : noncopyable
{
public:
typedef std::function<void(EventLoop*)> ThreadInitCallback;
EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(),
const string& name = string());
~EventLoopThread();
EventLoop* startLoop();
private:
void threadFunc();
EventLoop* loop_ GUARDED_BY(mutex_);
bool exiting_;
Thread thread_;
MutexLock mutex_;
Condition cond_ GUARDED_BY(mutex_);
ThreadInitCallback callback_;
};
开启事件循环,其实是在线程函数中执行EventLoop::loop(),
startLoop()返回EventLoop指针。
EventLoop* EventLoopThread::startLoop()
{
assert(!thread_.started());
thread_.start(); //执行线程函数
EventLoop* loop = NULL;
{
MutexLockGuard lock(mutex_);
while (loop_ == NULL)
{
cond_.wait(); //等待loop_
}
loop = loop_;
}
return loop;
}
//线程函数
void EventLoopThread::threadFunc()
{
EventLoop loop;
if (callback_)
{
callback_(&loop);//执行线程初始化回调函数,在构造类时注册
}
{
MutexLockGuard lock(mutex_);
loop_ = &loop;
cond_.notify(); //通知startLoop可返回EventLoop指针
}
loop.loop(); //开启事件循环
//assert(exiting_);
MutexLockGuard lock(mutex_);
loop_ = NULL;
}
EventLoopThreadPool源码分析
EventLoopThreadPool类
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()); //创建IO线程,开启事件循环
// valid after calling start()
/// round-robin
EventLoop* getNextLoop();//返回一个EventLoop指针
/// 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_; //TcpServer所在的EventLoop
string name_;
bool started_;
int numThreads_; //线程数
int next_;//新连接到来所选择的Eventloop对象的下标
std::vector<std::unique_ptr<EventLoopThread>> threads_; //存放EventLoopThread的vector
std::vector<EventLoop*> loops_; //存放EventLoop的vector
};
创建IO线程
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_);
}
}
取一个IO线程
这里采用最简单的round-robin算法来选取pool中的EventLoop。
即按数组下标依次取。
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;
}