TimerQueue类详解

来源:互联网 发布:c语言制表符是什么 编辑:程序博客网 时间:2024/06/01 19:13

说明:

TimerQueue构造中创建时间文件描述符timerfd_ 并关联的Channel 为timerfdChannel_,接着设置该Channel 的回调函数为TimerQueue::handleRead,当超时时刻去执行TimerQueue::handleRead,最后一句timerfdChannel_.enableReading();==>>

Channel::update()==>>即调用主线程中的loop_->updateChannel(this);==>>poller_->updateChannel(channel); 即EPollPoller类的EPollPoller::updateChannel函数

 

EPollPoller::updateChannel函数功能:

根据channel->index()知道是新的连接,先看key=socketfd 在channels_ 中是否存在,存在则

让event.data.ptr保存channel;并将该socketfd 加入epollfd_集合,Channel加入到EPollPoller::channels_;老的连接则将该socketfd 从epollfd_集合修改或者删除。

 

最后主线程中会调用loop->loop()功能

EPollPoller 类的poll 函数会收集所有发生事件的socketfd的Channel存于activeChannels_ 中,因为每一个socketfd 在对应的Channel 中会设置读/写/及错误发生时候的回调函数的;

下面即是遍历收集到的activeChannels_, 并执行每一个Channel 的handleEvent 进而去调用设置的回调函数;

当别的类想异步执行某个函数时候只需要调用EventLoop::runInLoop(const Functor& cb)

该函数里面会判断如果执行该函数的线程与主线程不同则利用往evtfd 中写个字符触发epoll ,继而这里得到执行了,即会执行上层注册的函数cb


因此:

看看TimerQueue::handleRead干了哪些活?

依次执行即将超时队列(按照距离超时的间隔从小到大放入的)中每个timer 的回调函数


TimerQueue.h

#ifndef MUDUO_NET_TIMERQUEUE_H
#define MUDUO_NET_TIMERQUEUE_H


#include <set>
#include <vector>


#include <boost/noncopyable.hpp>


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


namespace muduo
{
namespace net
{


class EventLoop;
class Timer;
class TimerId;


///
/// A best efforts timer queue.
/// No guarantee that the callback will be on time.
///
class TimerQueue : boost::noncopyable
{
 public:
  TimerQueue(EventLoop* loop);
  ~TimerQueue();


  ///
  /// Schedules the callback to be run at given time,
  /// repeats if @c interval > 0.0.
  ///
  /// Must be thread safe. Usually be called from other threads.
  TimerId addTimer(const TimerCallback& cb,
                   Timestamp when,
                   double interval);


  void cancel(TimerId timerId);


 private:


  // FIXME: use unique_ptr<Timer> instead of raw pointers.
  typedef std::pair<Timestamp, Timer*> Entry;
  typedef std::set<Entry> TimerList;
  typedef std::pair<Timer*, int64_t> ActiveTimer;
  typedef std::set<ActiveTimer> ActiveTimerSet;


  void addTimerInLoop(Timer* timer);
  void cancelInLoop(TimerId timerId);
  // called when timerfd alarms
  void handleRead();
  // move out all expired timers
  std::vector<Entry> getExpired(Timestamp now);
  void reset(const std::vector<Entry>& expired, Timestamp now);


  bool insert(Timer* timer);


  EventLoop* loop_;
  const int timerfd_;
  Channel timerfdChannel_;
  // Timer list sorted by expiration
  TimerList timers_;


  // for cancel()
  ActiveTimerSet activeTimers_;
  bool callingExpiredTimers_; /* atomic */
  ActiveTimerSet cancelingTimers_;
};


}
}
#endif  // MUDUO_NET_TIMERQUEUE_H


TimerQueue.cc

#define __STDC_LIMIT_MACROS
#include <muduo/net/TimerQueue.h>


#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/Timer.h>
#include <muduo/net/TimerId.h>


#include <boost/bind.hpp>


#include <sys/timerfd.h>


namespace muduo
{
namespace net
{
namespace detail
{
//可以利用timerfd 操作timer 
int createTimerfd()
{
 int timerfd = ::timerfd_create(CLOCK_MONOTONIC,
                                TFD_NONBLOCK | TFD_CLOEXEC);
 if (timerfd < 0)
 {
   LOG_SYSFATAL << "Failed in timerfd_create";
 }
 return timerfd;
}


/*将时间差以返回值: 秒, 纳秒存放*/
struct timespec howMuchTimeFromNow(Timestamp when)
{
//得到距离现在的时间差微妙
 int64_t microseconds = when.microSecondsSinceEpoch()
                        - Timestamp::now().microSecondsSinceEpoch();
 if (microseconds < 100)
 {
     microseconds = 100;
 }
 struct timespec ts;
 ts.tv_sec = static_cast<time_t>(
     microseconds / Timestamp::kMicroSecondsPerSecond);
 ts.tv_nsec = static_cast<long>(
     (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);
 return ts;
}


/*从时间文件描述符获得在now时刻有多少个定时器超时*/
void readTimerfd(int timerfd, Timestamp now)
{
 uint64_t howmany;
 ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
 LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
 if (n != sizeof howmany)
 {
   LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
 }
}


/*设置新的超时时间为newValue*/
void resetTimerfd(int timerfd, Timestamp expiration)
{
 // wake up loop by timerfd_settime()
 struct itimerspec newValue;
 struct itimerspec oldValue;
 bzero(&newValue, sizeof newValue);
 bzero(&oldValue, sizeof oldValue);
 newValue.it_value = howMuchTimeFromNow(expiration);
 int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
 if (ret)
 {
   LOG_SYSERR << "timerfd_settime()";
 }
}


}
}
}


using namespace muduo;
using namespace muduo::net;
using namespace muduo::net::detail;


/*
创建时间文件描述符timerfd_ 对应的Channel 为timerfdChannel_
并设置该Channel 的回调函数为TimerQueue::handleRead,
当超时时刻去执行TimerQueue::handleRead

*/
TimerQueue::TimerQueue(EventLoop* loop)
  : loop_(loop),
    timerfd_(createTimerfd()),
    timerfdChannel_(loop, timerfd_),
    timers_(),
    callingExpiredTimers_(false)
{
  timerfdChannel_.setReadCallback(
      boost::bind(&TimerQueue::handleRead, this));
  // we are always reading the timerfd, we disarm it with timerfd_settime.
  timerfdChannel_.enableReading();
}


TimerQueue::~TimerQueue()
{
  ::close(timerfd_);
  // do not remove channel, since we're in EventLoop::dtor();
  for (TimerList::iterator it = timers_.begin();
      it != timers_.end(); ++it)
  {
    delete it->second;
  }
}


/*
利用evfd 通知主线程中epoll 去执行函数TimerQueue::addTimerInLoop
*/
TimerId TimerQueue::addTimer(const TimerCallback& cb,
                             Timestamp when,
                             double interval)
{
  Timer* timer = new Timer(cb, when, interval);
  loop_->runInLoop(
      boost::bind(&TimerQueue::addTimerInLoop, this, timer));
  return TimerId(timer, timer->sequence());
}




/*
利用evfd 通知主线程中epoll 去执行函数TimerQueue::cancelInLoop
*/
void TimerQueue::cancel(TimerId timerId)
{
  loop_->runInLoop(
      boost::bind(&TimerQueue::cancelInLoop, this, timerId));
}


/*
将timer 插入TimerQueue的timers_ 和activeTimers_ 中
当插入的超时时间小于队列中第一个的超时时间,
则改变时间描述符的超时时间为timer;

*/
void TimerQueue::addTimerInLoop(Timer* timer)
{
  loop_->assertInLoopThread();
  bool earliestChanged = insert(timer);


  if (earliestChanged)
  {
    resetTimerfd(timerfd_, timer->expiration());
  }
}


/*
将activeTimers_ 和timers_ 中时间全部取消
*/
void TimerQueue::cancelInLoop(TimerId timerId)
{
  loop_->assertInLoopThread();
  assert(timers_.size() == activeTimers_.size());
  ActiveTimer timer(timerId.timer_, timerId.sequence_);
  ActiveTimerSet::iterator it = activeTimers_.find(timer);
  if (it != activeTimers_.end())
  {
    size_t n = timers_.erase(Entry(it->first->expiration(), it->first));
    assert(n == 1); (void)n;
    delete it->first; // FIXME: no delete please
    activeTimers_.erase(it);
  }
  else if (callingExpiredTimers_)
  {
    cancelingTimers_.insert(timer);
  }
  assert(timers_.size() == activeTimers_.size());
}


/*


*/
void TimerQueue::handleRead()
{
  loop_->assertInLoopThread();
  Timestamp now(Timestamp::now());
  readTimerfd(timerfd_, now);


 /*获得timers_ 中从小直到now 的timer 并返回
    即将超时的vector
*/
  std::vector<Entry> expired = getExpired(now);


  /*依次执行expired 中每个timer 的回调函数*/
  callingExpiredTimers_ = true;
  cancelingTimers_.clear();
  // safe to callback outside critical section
  for (std::vector<Entry>::iterator it = expired.begin();
      it != expired.end(); ++it)
  {
    it->second->run();
  }
  callingExpiredTimers_ = false;


  reset(expired, now);
}




/*
获得timers_ 中从小直到sentry 的timer 并返回
即即将超时的vector

*/
std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
{
  assert(timers_.size() == activeTimers_.size());
  std::vector<Entry> expired;
  
  /*时间==>>  Timer* */
  Entry sentry(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
  /*返回timers_ 中第一个大于等于值sentry 的位置*/
  TimerList::iterator end = timers_.lower_bound(sentry);
  assert(end == timers_.end() || now < end->first);


  /*也就是将timers_ 中从小直到sentry 拷贝到expired 中,再将其从
  timers_中删除*/
  std::copy(timers_.begin(), end, back_inserter(expired));
  timers_.erase(timers_.begin(), end);


  /*将expired 中的从activeTimers_ 中删除*/
  for (std::vector<Entry>::iterator it = expired.begin();
      it != expired.end(); ++it)
  {
    ActiveTimer timer(it->second, it->second->sequence());
    size_t n = activeTimers_.erase(timer);
    assert(n == 1); (void)n;
  }


  assert(timers_.size() == activeTimers_.size());
  return expired;
  
}




/*
说明:expired 为即将超时的vector 
  vector 中的timer 是循环使用的,且不存在于cancelingTimers_ 中,
  则将timer 插入TimerQueue::timers_ 和TimerQueue::activeTimers_ 中
  否则将其从expired 中删除;
  如果timers_ 不为空,则重新设置时间描述符timerfd_ 的超时
  时间为timers_中的第一个的超时时间;

*/
void TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
{
  Timestamp nextExpire;
  
  for (std::vector<Entry>::const_iterator it = expired.begin();
      it != expired.end(); ++it)
  {
    ActiveTimer timer(it->second, it->second->sequence());
    if (it->second->repeat()
        && cancelingTimers_.find(timer) == cancelingTimers_.end())
    {
      it->second->restart(now);
      insert(it->second);
    }
    else
    {
      // FIXME move to a free list
      delete it->second; // FIXME: no delete please
    }
  }


  if (!timers_.empty())
  {
    nextExpire = timers_.begin()->second->expiration();
  }


  if (nextExpire.valid())
  {
    resetTimerfd(timerfd_, nextExpire);
  }
}




/*
将timer 插入TimerQueue的timers_ 和activeTimers_ 中

注意: Entry(when, timer) 中when代表时间点,timer即是该时刻到来时刻对应的定时器。
*/
bool TimerQueue::insert(Timer* timer)
{
  loop_->assertInLoopThread();
  assert(timers_.size() == activeTimers_.size());
  bool earliestChanged = false;
  Timestamp when = timer->expiration();


  /*由于timers_ 是个set , STL中的set和map一样是有序的:

   当timer的时刻小于timers_中的第一个时候表明需要在addTimerInLoop函数调用中修改文件描述符的超时到来时刻为 timer->expiration();*/
  TimerList::iterator it = timers_.begin();
  if (it == timers_.end() || when < it->first)
  {
    earliestChanged = true;
  }


  /*when表示时刻点, 超时时候执行timer 的函数;
  将Entry(when, timer) 插入到timers_ 中
*/
  {
    std::pair<TimerList::iterator, bool> result
      = timers_.insert(Entry(when, timer));
    assert(result.second); (void)result;
  }


  /*timer->sequence()是个全局的编号, timer代表对应的定时器;
  将ActiveTimer(timer, timer->sequence() 插入到activeTimers_ 中
*/
  {
    std::pair<ActiveTimerSet::iterator, bool> result
      = activeTimers_.insert(ActiveTimer(timer, timer->sequence()));
    assert(result.second); (void)result;
  }


  assert(timers_.size() == activeTimers_.size());
  return earliestChanged;
}

0 0