EventLoop分析[1-4]

来源:互联网 发布:ubuntu snmp配置 编辑:程序博客网 时间:2024/05/17 08:36

首先看看是如何调用的:

int main(int argc, char* argv[])
{
  int numThreads = 0;
  if (argc > 1)
  {
    benchmark = true;
    Logger::setLogLevel(Logger::WARN);
    numThreads = atoi(argv[1]);
  }
  EventLoop loop;
  HttpServer server(&loop, InetAddress(8000), "dummy");
  server.setHttpCallback(onRequest);
  server.setThreadNum(numThreads);
  server.start();
  loop.loop();
}

主要看看EventLoop 的构造函数和EventLoop.loop()函数即可 


EventLoop.h

#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H


#include <vector>


#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>


#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/Callbacks.h>
#include <muduo/net/TimerId.h>


namespace muduo
{
namespace net
{


class Channel;
class Poller;
class TimerQueue;


///
/// Reactor, at most one per thread.
///
/// This is an interface class, so don't expose too much details.
class EventLoop : boost::noncopyable
{
 public:
  typedef boost::function<void()> Functor;


  EventLoop();
  ~EventLoop();  // force out-line dtor, for scoped_ptr members.


  ///
  /// Loops forever.
  ///
  /// Must be called in the same thread as creation of the object.
  ///
  void loop();


  void quit();


  ///
  /// Time when poll returns, usually means data arrivial.
  ///
  Timestamp pollReturnTime() const { return pollReturnTime_; }


  int64_t iteration() const { return iteration_; }


  /// Runs callback immediately in the loop thread.
  /// It wakes up the loop, and run the cb.
  /// If in the same loop thread, cb is run within the function.
  /// Safe to call from other threads.
  void runInLoop(const Functor& cb);
  /// Queues callback in the loop thread.
  /// Runs after finish pooling.
  /// Safe to call from other threads.
  void queueInLoop(const Functor& cb);


  // timers


  ///
  /// Runs callback at 'time'.
  /// Safe to call from other threads.
  ///
  TimerId runAt(const Timestamp& time, const TimerCallback& cb);
  ///
  /// Runs callback after @c delay seconds.
  /// Safe to call from other threads.
  ///
  TimerId runAfter(double delay, const TimerCallback& cb);
  ///
  /// Runs callback every @c interval seconds.
  /// Safe to call from other threads.
  ///
  TimerId runEvery(double interval, const TimerCallback& cb);
  ///
  /// Cancels the timer.
  /// Safe to call from other threads.
  ///
  void cancel(TimerId timerId);


  // internal usage
  void wakeup();
  void updateChannel(Channel* channel);
  void removeChannel(Channel* channel);


  // pid_t threadId() const { return threadId_; }
  void assertInLoopThread()
  {
    if (!isInLoopThread())
    {
      abortNotInLoopThread();
    }
  }
  bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
  // bool callingPendingFunctors() const { return callingPendingFunctors_; }
  bool eventHandling() const { return eventHandling_; }


  static EventLoop* getEventLoopOfCurrentThread();


 private:
  void abortNotInLoopThread();
  void handleRead();  // waked up
  void doPendingFunctors();


  void printActiveChannels() const; // DEBUG


  typedef std::vector<Channel*> ChannelList;


  bool looping_; /* atomic */
  bool quit_; /* atomic */
  bool eventHandling_; /* atomic */
  bool callingPendingFunctors_; /* atomic */
  int64_t iteration_;
  const pid_t threadId_;
  Timestamp pollReturnTime_;
  boost::scoped_ptr<Poller> poller_;
  boost::scoped_ptr<TimerQueue> timerQueue_;
  int wakeupFd_;
  // unlike in TimerQueue, which is an internal class,
  // we don't expose Channel to client.
  boost::scoped_ptr<Channel> wakeupChannel_;
  ChannelList activeChannels_;
  Channel* currentActiveChannel_;
  MutexLock mutex_;
  std::vector<Functor> pendingFunctors_; // @BuardedBy mutex_
};


}
}
#endif  // MUDUO_NET_EVENTLOOP_H


EventLoop.cc

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.


// Author: Shuo Chen (chenshuo at chenshuo dot com)


#include <muduo/net/EventLoop.h>


#include <muduo/base/Logging.h>
#include <muduo/base/Mutex.h>
#include <muduo/net/Channel.h>
#include <muduo/net/Poller.h>
#include <muduo/net/SocketsOps.h>
#include <muduo/net/TimerQueue.h>


#include <boost/bind.hpp>


#include <signal.h>
#include <sys/eventfd.h>


using namespace muduo;
using namespace muduo::net;


/*
仅限于本文件使用
IgnoreSigPipe() 当对端socket 关闭了,再write 时候进程默认是收到
   SIGPIPE信号而终止,这里忽略此信号
createEventfd() 用于线程间通信的

*/
namespace
{
__thread EventLoop* t_loopInThisThread = 0;


const int kPollTimeMs = 10000;


int createEventfd()
{
 int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
 if (evtfd < 0)
 {
   LOG_SYSERR << "Failed in eventfd";
   abort();
 }
 return evtfd;
}


#pragma GCC diagnostic ignored "-Wold-style-cast"
class IgnoreSigPipe
{
public:
 IgnoreSigPipe()
 {
   ::signal(SIGPIPE, SIG_IGN);
   LOG_TRACE << "Ignore SIGPIPE";
 }
};
#pragma GCC diagnostic error "-Wold-style-cast"


IgnoreSigPipe initObj;
}


EventLoop* EventLoop::getEventLoopOfCurrentThread()
{
  return t_loopInThisThread;
}


/*
*/
EventLoop::EventLoop()
  : looping_(false),
    quit_(false),
    eventHandling_(false),
    callingPendingFunctors_(false),
    iteration_(0),
    threadId_(CurrentThread::tid()),
    poller_(Poller::newDefaultPoller(this)),/*创建对象EPollPoller*/
    timerQueue_(new TimerQueue(this)),
    wakeupFd_(createEventfd()),
    /*创建evtfd 并关联对应的Channel, 该对象里面设置读写及错误发生时候的回调函数*/
    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;
 }


 /*给evtfd 设置读函数*/
 wakeupChannel_->setReadCallback(
     boost::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();
  ::close(wakeupFd_);
  t_loopInThisThread = NULL;
}


/*


*/
void EventLoop::loop()
{
  assert(!looping_);
  assertInLoopThread();
  looping_ = true;
  quit_ = false;
  LOG_TRACE << "EventLoop " << this << " start looping";


  while (!quit_)
  {
  /*
EPollPoller 类的poll 函数会收集所有发生事件的socketfd 的Channel
存于activeChannels_ 中;

这里的EventLoop::activeChannels_就是EPollPoller 类的poll 函数中用于填充的发生事件的socketfd的Channel
*/
    activeChannels_.clear();
    pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
    ++iteration_;
    if (Logger::logLevel() <= Logger::TRACE)
    {
      printActiveChannels();
    }


    /*
因为每一个socketfd 在对应的Channel 中会设置
读/写/及错误发生时候的回调函数的;
下面即是遍历收集到的activeChannels_ , 并执行每一个
Channel 的handleEvent 进而去调用设置的回调函数;

*/
    eventHandling_ = true;
    for (ChannelList::iterator it = activeChannels_.begin();
        it != activeChannels_.end(); ++it)
    {
      currentActiveChannel_ = *it;
      currentActiveChannel_->handleEvent(pollReturnTime_);
    }
    currentActiveChannel_ = NULL;
    eventHandling_ = false;


/*
当别的类想异步执行某个函数时候
只需要调用EventLoop::runInLoop(const Functor& cb)
该函数里面会判断如果执行该函数的线程与主线程不同
则利用往evtfd 中写个字符触发epoll , 继而这里得到执行了,
即会执行上层注册的函数cb

*/
    doPendingFunctors();
  }


  LOG_TRACE << "EventLoop " << this << " stop looping";
  looping_ = false;
}


void EventLoop::quit()
{
  quit_ = true;
  if (!isInLoopThread())
  {
    wakeup();
  }
}


void EventLoop::runInLoop(const Functor& cb)
{
  if (isInLoopThread())
  {
    cb();
  }
  else
  {
    queueInLoop(cb);
  }
}


void EventLoop::queueInLoop(const Functor& cb)
{
  {
  MutexLockGuard lock(mutex_);
  pendingFunctors_.push_back(cb);
  }


  if (!isInLoopThread() || callingPendingFunctors_)
  {
    wakeup();
  }
}


TimerId EventLoop::runAt(const Timestamp& time, const TimerCallback& cb)
{
  return timerQueue_->addTimer(cb, time, 0.0);
}


TimerId EventLoop::runAfter(double delay, const TimerCallback& cb)
{
  Timestamp time(addTime(Timestamp::now(), delay));
  return runAt(time, cb);
}


TimerId EventLoop::runEvery(double interval, const TimerCallback& cb)
{
  Timestamp time(addTime(Timestamp::now(), interval));
  return timerQueue_->addTimer(cb, time, interval);
}


void EventLoop::cancel(TimerId timerId)
{
  return timerQueue_->cancel(timerId);
}


/*
调用EPollPoller 类的updateChannel
*/
void EventLoop::updateChannel(Channel* channel)
{
  assert(channel->ownerLoop() == this);
  assertInLoopThread();
  poller_->updateChannel(channel);
}


/*
调用EPollPoller 类的removeChannel
*/
void EventLoop::removeChannel(Channel* channel)
{
  assert(channel->ownerLoop() == this);
  assertInLoopThread();
  if (eventHandling_)
  {
    assert(currentActiveChannel_ == channel ||
        std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());
  }
  poller_->removeChannel(channel);
}


void EventLoop::abortNotInLoopThread()
{
  LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this
            << " was created in threadId_ = " << threadId_
            << ", current thread id = " <<  CurrentThread::tid();
}


void EventLoop::wakeup()
{
  uint64_t one = 1;
  ssize_t n = sockets::write(wakeupFd_, &one, sizeof one);
  if (n != sizeof one)
  {
    LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8";
  }
}


void EventLoop::handleRead()
{
  uint64_t one = 1;
  ssize_t n = sockets::read(wakeupFd_, &one, sizeof one);
  if (n != sizeof one)
  {
    LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8";
  }
}


void EventLoop::doPendingFunctors()
{
  std::vector<Functor> functors;
  callingPendingFunctors_ = true;


  {
  MutexLockGuard lock(mutex_);
  functors.swap(pendingFunctors_);
  }


  for (size_t i = 0; i < functors.size(); ++i)
  {
    functors[i]();
  }
  callingPendingFunctors_ = false;
}




void EventLoop::printActiveChannels() const
{
  for (ChannelList::const_iterator it = activeChannels_.begin();
      it != activeChannels_.end(); ++it)
  {
    const Channel* ch = *it;
    LOG_TRACE << "{" << ch->reventsToString() << "} ";
  }
}

总结:

EventLoop::loop会调用EPollPoller 类的poll函数将发生事件的socketfd的Channel存于EventLoop::activeChannels,接着loop函数中会去

执行EventLoop::activeChannels中每一个Channel的handleEvent函数,即会去执行注册给该socketfd的Channel的函数;还有就是用户通过envfd线程通信触发的epoll去执行用户的函数。

EventLoop::updateChannel(Channel* channel)会调用EPollPoller 类的updateChannel(channel);

EventLoop::removeChannel(Channel* channel)会调用EPollPoller 类的removeChannel(channel)


下来的问题?

监听套接字对应的Channel设置的回调函数在哪设置的,即监听套接字对应的Channel的建立地方;

客户连接套接字对应的Channel设置的回调函数在哪设置的,即客户连接套接对应的Channel的建立地方;

int main(int argc, char* argv[])
{
  int numThreads = 0;
  if (argc > 1)
  {
    benchmark = true;
    Logger::setLogLevel(Logger::WARN);
    numThreads = atoi(argv[1]);
  }
  EventLoop loop;
  HttpServerserver(&loop, InetAddress(8000), "dummy");
  server.setHttpCallback(onRequest);
  server.setThreadNum(numThreads);
  server.start();                   //该函数会告诉我们答案的
  loop.loop();
}

0 0
原创粉丝点击