说明
IO线程池,封装多个IO线程EventLoopThread,并保存每个IO的线程的loop。
成员变量
重点关注:
numThreads:在start之前设置,创建指定数量的IO线程。
thread_:start之后创建的所有线程对象保存起来。
loops: start之后每个thread返回的栈变量指针EventLoop*.即不同IO线程的事件循环。
index: 为TcpServer的新Tcp连接分配loop, 通过轮询分发,index自增。
EventLoop* baseLoop_; //与Acceptor所属EventLoop相同,主线程loop
string name_;
bool started_; //是否开始,在start()函数中赋值为true
int numThreads_; //线程数量
int next_; //新连接到来时,所选择的EventLoop对象下标
std::vector<std::unique_ptr<EventLoopThread>> threads_; //IO线程列表
std::vector<EventLoop*> loops_; //EventLoop列表
方法
1. void setThreadNum:设置IO线程数量
void setThreadNum(int numThreads) { numThreads_ = numThreads; }
2. start: 启动线程池,创建若干线程并加入到threads_当中, 并保存线程启动后所有的loop*,为TcpServer的新Tcp连接分配loop要用。
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); //创建IO线程
threads_.push_back(std::unique_ptr<EventLoopThread>(t)); //保存IO线程
loops_.push_back(t->startLoop()); //保存IO线程私有的Eventloop到线程池容器中。供acceptor分配socket连接使用
}
if (numThreads_ == 0 && cb)
{
cb(baseLoop_);
}
}
3. getNextLoop:轮询方法为TcpServer的新连接分配loop,index增加。
//轮询
EventLoop* EventLoopThreadPool::getNextLoop()
{
baseLoop_->assertInLoopThread();
assert(started_);
EventLoop* loop = baseLoop_; //默认是主loop,loops不为空时loop是线程池中的loop。
if (!loops_.empty())
{
// round-robin
loop = loops_[next_];
++next_;
if (implicit_cast<size_t>(next_) >= loops_.size()) //这里implicit_cast是muduo自己封装的转换
{
next_ = 0;
}
}
return loop;
}
还有另一种hash方法,取模返回loop
EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode)
{
baseLoop_->assertInLoopThread();
EventLoop* loop = baseLoop_;
if (!loops_.empty())
{
loop = loops_[hashCode % loops_.size()];
}
return loop;
}