模型
实现流程:
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_;
};