muduo源码分析之EventLoop事件循环
相关文件
muduo/net/EventLoop.h
muduo/net/EventLoop.cc
作用
EventLoop,顾名思义,事件循环。
创建了EventLoop对象的线程是IO线程,主要功能是运行事件循环EventLoop::loop()。
个人理解为调用poll/epoll的那个while循环。
使用
在loop方法中会调用poll/epoll监听事件,其中又涉及到Poller类和Channel类。
#include <muduo/net/EventLoop.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
int main(void)
{
printf("main(): pid = %d, tid = %d\n",
getpid(), CurrentThread::tid());
EventLoop loop;
loop.loop();
return 0;
}
EventLoop源码分析
本节仅从one loop per thread的角度小窥一下EventLoop的源码,涉及到Poller部分在Reactor小节在深入理解。
one loop per thread即一个线程只能有一个EventLoop对象。
EventLoop对象在构造时,会检查当前线程是否创建了其他EventLoop对象,如果已创建就终止程序(LOG_FATAL)。
构造函数
__thread EventLoop* t_loopInThisThread = 0; //__thread表示是线程自己占有的变量,指向当前线程创建的Eventloop对象
EventLoop::EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false),
callingPendingFunctors_(false),
iteration_(0),
threadId_(CurrentThread::tid()), //当前线程的tid
poller_(Poller::newDefaultPoller(this)),
timerQueue_(new TimerQueue(this)),
wakeupFd_(createEventfd()),
wakeupChannel_(new Channel(this, wakeupFd_)),
currentActiveChannel_(NULL)
{
LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_;
if (t_loopInThisThread) //不为空,表示已经创建,终止程序
{
LOG_FATAL << "Another EventLoop " << t_loopInThisThread
<< " exists in this thread " << threadId_;
}
else
{
t_loopInThisThread = this;
}
//暂时不用管这部分
wakeupChannel_->setReadCallback(
std::bind(&EventLoop::handleRead, this));
// we are always reading the wakeupfd
wakeupChannel_->enableReading();
}
EventLoop::~EventLoop()
{
LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_
<< " destructs in thread " << CurrentThread::tid();
wakeupChannel_->disableAll();
wakeupChannel_->remove();
::close(wakeupFd_);
t_loopInThisThread = NULL; //在析构函数中将其置空
}
负面测试
在主线程创建了EventLoop对象,试图在另一个线程调用其loop方法,导致程序异常终止
#include <muduo/net/EventLoop.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
muduo::EventLoop* g_loop;
void threadFunc()
{
g_loop.loop();
}
int main(void)
{
EventLoop loop;
g_loop = &loop;
Thread t(threadFunc); //创建线程
t.start();
t.join();
return 0;
}
loop()干了什么
作为EventLoop的主要方法,这里不深入看Poller和Chanel的源码,先留个大致的印象。
void EventLoop::loop()
{
assert(!looping_);
assertInLoopThread(); //检查是否在创建EventLoop的线程中调用
looping_ = true; //开始循环
quit_ = false; // 退出标志
LOG_TRACE << "EventLoop " << this << " start looping";
while (!quit_)
{
activeChannels_.clear(); //vector :活跃的Cannel
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);//poll
++iteration_;
if (Logger::logLevel() <= Logger::TRACE) //开发时写日志
{
printActiveChannels();
}
// TODO sort channel by priority
eventHandling_ = true; //处理poll得到的事件
//这里的一个cannel可理解为一个文件描述符和如何处理它的事件的回调函数的封装
for (Channel* channel : activeChannels_)
{
currentActiveChannel_ = channel;
currentActiveChannel_->handleEvent(pollReturnTime_);//处理fd的事件
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
doPendingFunctors();
}
LOG_TRACE << "EventLoop " << this << " stop looping";
looping_ = false;
}