muduo源码分析之EventLoop事件循环
相关文件
muduo/net/EventLoop.h
muduo/net/EventLoop.cc
作用
EventLoop,顾名思义,事件循环。
创建了EventLoop对象的线程是IO线程,主要功能是运行事件循环EventLoop::loop()。
个人理解为调用poll/epoll的那个while循环。
使用
在loop方法中会调用poll/epoll监听事件,其中又涉及到Poller类和Channel类。
#include 
#include 
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 
#include 
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;
}