读Muduo源码笔记---8(定时器)

muduo的定时器由三个类实现,TimerId、Timer、TimerQueue。

1、采用timer_create函数得到定时器对象

      timerfd_create把时间变成了一个文件描述符,该“文件”在定时器超时的那一刻变得可读,这样就能很方便的融入到select/poll框架中,用统一的方式来处理I/O和超时事件,这正是Reactor模式的长处。

2、Timer类

     Timer是对定时器的高层次抽象,封装了定时器的一些参数,例如超时回调函数、超时时间、超时时间间隔、定时器是否重复、定时器的序列号。其函数大都是设置这些参数,run()用来调用回调函数,restart()用来重启定时器(如果设置为重复)。

class Timer : boost::noncopyable
{
 public:
  void run() const  //run函数来调用回调函数
  {
    callback_();
  }

  Timestamp expiration() const  { return expiration_; }
  bool repeat() const { return repeat_; }
  int64_t sequence() const { return sequence_; }

  void restart(Timestamp now);

  static int64_t numCreated() { return s_numCreated_.get(); }

 private:
  const TimerCallback callback_;//超时回调函数
  Timestamp expiration_;        //超时时间
  const double interval_;       //超时时间间隔
  const bool repeat_;           //定时器是否重复
  const int64_t sequence_;      //定时器的序列号

  static AtomicInt64 s_numCreated_;
};

//重复定时
void Timer::restart(Timestamp now)
{
  if (repeat_)//定时器是否重复
  {
    expiration_ = addTime(now, interval_);//计算超时时间
  }
  else
  {
    expiration_ = Timestamp::invalid();//return Timestamp()获取一个无效时间
  }
}

3、TimerQueue

    TimerQueue的接口很简单,只有两个函数addTimer()和cancel()。它的内部有channel,和timerfd相关联。添加新的Timer后,在超时后,timerfd可读,会处理channel事件,之后调用Timer的回调函数;在timerfd的事件处理后,还有检查一遍超时定时器,如果其属性为重复还有再次添加到定时器集合中。

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 instead of raw pointers.
  // unique_ptr是C++ 11标准的一个独享所有权的智能指针
  // 无法得到指向同一对象的两个unique_ptr指针
  // 但可以进行移动构造与移动赋值操作,即所有权可以移动到另一个对象(而非拷贝构造)
  typedef std::pair Entry;
  typedef std::set TimerList;
  typedef std::pair ActiveTimer;
  typedef std::set ActiveTimerSet;
 
  // 以下成员函数只可能在其所属的I/O线程中调用,因而不必加锁。
  // 服务器性能杀手之一是锁竞争,所以要尽可能少用锁
  void addTimerInLoop(Timer* timer);
  void cancelInLoop(TimerId timerId);
  // called when timerfd alarms
  void handleRead();
  // move out all expired timers
  // 返回超时的定时器列表
  std::vector getExpired(Timestamp now);
  void reset(const std::vector& expired, Timestamp now);
 
  bool insert(Timer* timer);
 
  EventLoop* loop_;		// 所属EventLoop
  const int timerfd_;
  Channel timerfdChannel_;
  // Timer list sorted by expiration
  TimerList timers_;	// timers_是按到期时间排序
 
  // for cancel()
  // timers_与activeTimers_保存的是相同的数据
  // timers_是按到期时间排序,activeTimers_是按对象地址排序
  ActiveTimerSet activeTimers_;
  bool callingExpiredTimers_; /* atomic */
  ActiveTimerSet cancelingTimers_;	// 保存的是被取消的定时器
};

//.cpp
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);//启动和停止定时器;0表示相对时间,第三个参数视为相对于调用timerfd_settime()时间点的相对时间,第四个返回定时器的前一设置
  if (ret)
  {
    LOG_SYSERR << "timerfd_settime()";
  }
}

bool TimerQueue::insert(Timer* timer)
{
  loop_->assertInLoopThread();
  assert(timers_.size() == activeTimers_.size());
  bool earliestChanged = false;
  Timestamp when = timer->expiration();//获取定时时间
  TimerList::iterator it = timers_.begin();//获取定时列表中的迭代器
  if (it == timers_.end() || when < it->first)//判断定时列表是否为空或者当前插入时间是否小于列表中的第一个
  {
    earliestChanged = true;
  }
//插入两个时间列表中TimerList,ActiveTimerSet
  {
    std::pair result
      = timers_.insert(Entry(when, timer));
    assert(result.second); (void)result;
  }
  {
    std::pair result
      = activeTimers_.insert(ActiveTimer(timer, timer->sequence()));
    assert(result.second); (void)result;
  }

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


//添加定时器到列表
void TimerQueue::addTimerInLoop(Timer* timer)
{
  loop_->assertInLoopThread();
  bool earliestChanged = insert(timer);//插入到定时列表中

  if (earliestChanged)
  {
    resetTimerfd(timerfd_, timer->expiration());//定时列表为空或插入的时间比定时列表中的小更新定时器定时时间
  }
}

//获取超时时间,并保存在vector中
std::vector TimerQueue::getExpired(Timestamp now)
{
  assert(timers_.size() == activeTimers_.size());
  std::vector expired;
  Entry sentry(now, reinterpret_cast(UINTPTR_MAX));

  TimerList::iterator end = timers_.lower_bound(sentry);//最后一个小于指定时间的下一个位置

  assert(end == timers_.end() || now < end->first);
  std::copy(timers_.begin(), end, back_inserter(expired));//将满足超时的Entry拷贝到expired中
  timers_.erase(timers_.begin(), end);//在timers_列表中删除

  for (std::vector::iterator it = expired.begin();
      it != expired.end(); ++it)                        //将满足超时条件的timer从activeTimers_删去
  {
    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;   //返回满足超时的Entry的vector
}

void TimerQueue::reset(const std::vector& expired, Timestamp now)
{
  Timestamp nextExpire;
  //遍历超时时间数组,查找每一个timer是否设置为repeat且该定时器没有被放在cancelingTimers_中
  for (std::vector::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  //不满足条件删除timer
    {
      // FIXME move to a free list
      delete it->second; // FIXME: no delete please
    }
  }

  if (!timers_.empty())//最后判断timers_是否为空,不为空将第一个元素的值的expiration取出。
  {
    nextExpire = timers_.begin()->second->expiration();
  }

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

//chanel的回调函数,判断timerfd是可读,这也就是在插入定时时间是更新timerfd的原因
void TimerQueue::handleRead()
{
  loop_->assertInLoopThread();
  Timestamp now(Timestamp::now());//获取当前时间
  readTimerfd(timerfd_, now);//判断是否可读,主要是通过read(timerfd, &howmany, sizeof howmany)不可读则阻塞

  std::vector expired = getExpired(now);//获取超时timer,

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

  reset(expired, now);
}

//取消
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_) //若不在判断callingExpiredTimers_
  {
    cancelingTimers_.insert(timer);//说明其在超时处理中从activeTimers_中取出,因此,把它插入
                                    //cancelingTimers_
  }
  assert(timers_.size() == activeTimers_.size());
}

 

你可能感兴趣的:(muduo源码读书笔记)