muduo网络库——TimerQueue

模型

img

实现流程:

TimerQueue类主要用来设置超时任务,通过std::set数据结构来管理Timer。由于std::set的底层实现原理是二叉树,时间复杂度为O(logN), 其内部可以对管理的时间进行自动排序,这样优化了任务时间的排序流程,能方便且及时的查找出超时的任务,做相应删除等操作。

源码分析

TimerQueue

构造函数

如代码所示,在构造函数时即设置了Channel回调,Channel的对象由构造时传入,这样当Channel有通过Eventloop收到poller的激活事件回调时,即可在TimerQueue判断任务是否超时并做相应处理。

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

handleRead

handleRead函数主要用来处理超时任务,其要求必须在当前loop线程中使用。

主要流程:

1)getExpired获取超时的任务;

2)超时任务执行;

3)对周期定时任务进行重置,释放一次性定时任务;

void TimerQueue::handleRead()
{
  loop_->assertInLoopThread();   
  Timestamp now(Timestamp::now());
  readTimerfd(timerfd_, now);
    
  std::vector<Entry> expired = getExpired(now);  

  callingExpiredTimers_ = true;
  cancelingTimers_.clear();
  // safe to callback outside critical section
  for (const Entry& it : expired)
  {
    it.second->run();
  }
  callingExpiredTimers_ = false;

  reset(expired, now);
}

std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
{
  assert(timers_.size() == activeTimers_.size());
  std::vector<Entry> expired;
  Entry sentry(now, reinterpret_cast<Timer*>(UINTPTR_MAX)); // 获取已当前时间为基准的Entry
  TimerList::iterator end = timers_.lower_bound(sentry);    // lower_bound返回大于等于sentry的时间列表 即超时列表
  assert(end == timers_.end() || now < end->first);
  std::copy(timers_.begin(), end, back_inserter(expired)); // 将timers_中的内容拷贝至临时超时列表expired中
  timers_.erase(timers_.begin(), end);  // timers_中删除所有超时任务

  for (const Entry& it : expired)  
  {
    ActiveTimer timer(it.second, it.second->sequence());
    size_t n = activeTimers_.erase(timer);   // 删除活跃队列中的timer, 因为此时这部分timer已超时
    assert(n == 1); (void)n;
  }

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

Entry

Entry可以看作是一个Timer对象的组合,key是时间戳,value是Timer对象指针,在TimerQueue中放入TImeList中管理,TimerList是由std::set维护,方便自动排序。

typedef std::pair<Timestamp, Timer*> Entry;
typedef std::set<Entry> TimerList;

// 管理队列
TimerList timers_;

// 活跃队列
ActiveTimerSet activeTimers_;

addTimer

addTimer是在EventLoop中被调用的,调用代码如下:

// 功能: 用户指定绝对时间
// TimerId: 保证Timer对象的唯一性
// cb: 超时回调函数 是在Timer类中的run函数中调用
// time: 时间戳 用于TimerQueue中任务是否超时
TimerId EventLoop::runAt(Timestamp time, TimerCallback cb)
{
  return timerQueue_->addTimer(std::move(cb), time, 0.0);
}

// 功能: 用户指定相对时间
TimerId EventLoop::runAfter(double delay, TimerCallback cb)
{
  Timestamp time(addTime(Timestamp::now(), delay));
  return runAt(time, std::move(cb));
}

// 功能: 用户指定周期 重复运行
TimerId EventLoop::runEvery(double interval, TimerCallback cb)
{
  Timestamp time(addTime(Timestamp::now(), interval));
  return timerQueue_->addTimer(std::move(cb), time, interval);
}

addTimer源码如下:

TimerId TimerQueue::addTimer(TimerCallback cb,
                             Timestamp when,
                             double interval)
{
  Timer* timer = new Timer(std::move(cb), when, interval);   // 在TimerQueue中创建Timer对象
  loop_->runInLoop(
      std::bind(&TimerQueue::addTimerInLoop, this, timer));  // 保证在当前loop线程中运行
  return TimerId(timer, timer->sequence());                  // 返回唯一标识
}

// 回调函数处理 保存当前超时任务
void TimerQueue::addTimerInLoop(Timer* timer)
{
  loop_->assertInLoopThread();
  bool earliestChanged = insert(timer);

  if (earliestChanged)   // 如果超时 则重置
  {
    resetTimerfd(timerfd_, timer->expiration());
  }
}

// 插入
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)  // 定时器集合为空 或者 新添加的timer已经超时(当前时间小于队列中的最早时间)
  {
    earliestChanged = true;
  }
  {
    std::pair<TimerList::iterator, bool> result
      = timers_.insert(Entry(when, timer));     // timers_内插入时间管理对象
    assert(result.second); (void)result;
  }
  {
    std::pair<ActiveTimerSet::iterator, bool> result
      = activeTimers_.insert(ActiveTimer(timer, timer->sequence()));  // activeTimers_内插入时间管理对象
    assert(result.second); (void)result;
  }

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

reset

void TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
{
  Timestamp nextExpire;

  for (const Entry& it : expired)
  {
    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

Timer类代表一个超时任务,但并不直接绑定Channel。Timer主要包含超时时刻(expiration_),超时回调(callback_),周期时间值(interval_),全局唯一id(sequence_)。

超时回调

超时回调函数主要是在TimerQueue处理超时任务时被调用。

void run() const
{
  callback_();
}

重启定时器

void Timer::restart(Timestamp now)
{
  if (repeat_)
  {
    expiration_ = addTime(now, interval_);
  }
  else
  {
    expiration_ = Timestamp::invalid();
  }
}

唯一序列号

# 构造时传入
Timer(TimerCallback cb, Timestamp when, double interval)
    : callback_(std::move(cb)),
      expiration_(when),
      interval_(interval),
      repeat_(interval > 0.0),
      sequence_(s_numCreated_.incrementAndGet())   // 唯一序列号
  { }
    
# 获取全局序列号
int64_t sequence() const { return sequence_; }

TimerId

TimerId来主要用来作为Timer的唯一标识。Timer构造时会创建唯一序列号,传给TimerId来维护。

class TimerId : public muduo::copyable
{
 public:
  TimerId()
    : timer_(NULL),
      sequence_(0)
  {
  }

  TimerId(Timer* timer, int64_t seq)
    : timer_(timer),
      sequence_(seq)
  {
  }

  // default copy-ctor, dtor and assignment are okay

  friend class TimerQueue;

 private:
  Timer* timer_;
  int64_t sequence_;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值