EventLoop是一个事件循环,遵循one-thread-one-loop,用于运行和管理epoll。只要该loop启动后,将一直循环这样一个事件循环。
数据成员:
bool looping_; //用于标志该loop是否运行起来
//epoll结构,事件循环的核心部分。其生命周期由EventLoop控制
shared_ptr<Epoll> poller_;
//唤醒通道,用于线程间的通信,主要是通知唤醒一个阻塞于epoll_wait中的Eventloop
int wakupfd_;
bool quit_; //标志退出状态
bool eventHandling; //标志是否处于回调各个有事件产生的通道的回调函数过程中
mutable Mutexlock mutex_; //锁,跨线程注册Channel的时候需要加锁
std::vector<Funtor> pendingFunctors_;
bool callingPendingFunctors_;
const pid_t threadId_;
shared_ptr<Channel> pwakeupChannel_; //通知通道,用于MainReactor唤醒SubReactor
主要是创建事件分发器Epoll和唤醒通道
EventLoop::EventLoop()
: looping_(false),
poller_(new Epoll()),
wakeupFd_(createEventfd()),
quit_(false),
eventHandling_(false),
callingPendingFunctors_(false),
threadId_(CurrentThread::tid()),
pwakeupChannel_(new Channel(this, wakeupFd_))
{
if (t_loopInThisThread)
{
//LOG << "Another EventLoop " << t_loopInThisThread << " exists in this thread " << threadId_;
}
else
{
t_loopInThisThread = this;
}
//pwakeupChannel_->setEvents(EPOLLIN | EPOLLET | EPOLLONESHOT);
pwakeupChannel_->setEvents(EPOLLIN | EPOLLET);
pwakeupChannel_->setReadHandler(bind(&EventLoop::handleRead, this));
pwakeupChannel_->setConnHandler(bind(&EventLoop::handleConn, this));
poller_->epoll_add(pwakeupChannel_, 0);
}
void EventLoop::loop()
{
assert(!looping_);
assert(isInLoopThread());
looping_ = true;
quit_ = false;
//LOG_TRACE << "EventLoop " << this << " start looping";
std::vector<SP_Channel> ret;
while (!quit_)
{
//cout << "doing" << endl;
ret.clear();
//poll_wait和getEventRequest函数返回
ret = poller_->poll();
//调用每一个活跃Channel中相应事件的回调函数,完成事件处理
eventHandling_ = true;
for (auto &it : ret)
it->handleEvents();
eventHandling_ = false;
//执行其他线程调用queueinloop添加进去的函数队列
doPendingFunctors();
//调用定时器处理超期连接
poller_->handleExpired();
}
looping_ = false;
}
/*如果在当前线程中调用本线程Eventloop对象的runInLoop,那么直接执行回调函数.
如果该EventLoop不在当前线程中,那么将调用queueInloop把该回调函数放到待执行
回调函数队列的末尾,并通过写eventfd唤醒该EventLoop线程。
*/
void EventLoop::runInLoop(Functor&& cb)
{
if (isInLoopThread())
cb();
else
queueInLoop(std::move(cb));
}
/*本线程也可以调用queueInloop将cb放到待执行函数队列中,如果该EventLoop
正处于loop函数中的执行callingPendingFunctors阶段,就需要写eventfd,否则
如果下一次一直没有事件产生,可能会影响下一次doPendingFunctors()的执行时间,
导致新添加的回调函数的执行为无限期拖后*/
void EventLoop::queueInLoop(Functor&& cb)
{
{
MutexLockGuard lock(mutex_);
pendingFunctors_.emplace_back(std::move(cb));
}
if (!isInLoopThread() || callingPendingFunctors_)
wakeup();
}
移动语义和右值引用可以减少拷贝,节约开销。
EventLoop的wakefd就是通过eventfd创建出来的
int createEventfd()
{
int evtfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (evtfd < 0)
{
LOG << "Failed in eventfd";
abort();
}
return evtfd;
}
类似的用于线程间通信还有sockpair和pipe,但是另外两个都需要两个描述符,而evenfd只需要一个描述符就可以,更节省开销。
eventfd这个文件描述符的上层持有者是eventloop,其回调函数有两个:
void EventLoop::handleRead()
{
uint64_t one = 1;
ssize_t n = readn(wakeupFd_, &one, sizeof one);
if (n != sizeof one)
{
LOG << "EventLoop::handleRead() reads " << n << " bytes instead of 8";
}
//pwakeupChannel_->setEvents(EPOLLIN | EPOLLET | EPOLLONESHOT);
//执行完读操作后重新注册读事件
pwakeupChannel_->setEvents(EPOLLIN | EPOLLET);
}
//由Channel类的handleEvents函数可知,此函数在执行完读回调函数之后执行,更新注册pwakeupChannel事件
void EventLoop::handleConn()
{
//poller_->epoll_mod(wakeupFd_, pwakeupChannel_, (EPOLLIN | EPOLLET | EPOLLONESHOT), 0);
updatePoller(pwakeupChannel_, 0);
}
void removeFromPoller(shared_ptr<Channel> channel)
{
//shutDownWR(channel->getFd());
poller_->epoll_del(channel);
}
void updatePoller(shared_ptr<Channel> channel, int timeout = 0)
{
poller_->epoll_mod(channel, timeout);
}
void addToPoller(shared_ptr<Channel> channel, int timeout = 0)
{
poller_->epoll_add(channel, timeout);
}
这些函数只会在EventLoop本线程内调用。