定时器类图
TimerQueue数据结构的选择:
能快速根据当前时间找到已到期的定时器,也要高效的添加和删除Timer,因而可以用二叉搜索树,用map或者set
typedef std::pair<Timestamp, Timer*> Entry;
typedef std::set TimerList;
三个类的作用:
TimerId:用户只能看到这个类,其包含一个定时器及其序号,cancel()函数用这个类来取消定时器。
Timer:该类是一个定时器的封装,其包含定时器的内部实现细节。
TimerQueue:该类是定时器处理流程的封装,其对外接口只有addtime()和cancel()。定时器的使用要通过EventLoop,EventLoop把addtime()和cancel()封装成更好用的runAt(),runAfter(),runEvery()等函数。
时序图:
1.TimerId类
数据成员:
Timer* timer_:定时器timer_
int64_t sequence_:定时器的序号,每个定时器都有唯一的一个编号
成员函数:
TimerId():构造函数
TimerId(Timer* timer, int64_t seq):构造函数
TimerId.h
#ifndef MUDUO_NET_TIMERID_H
#define MUDUO_NET_TIMERID_H
#include <muduo/base/copyable.h>
namespace muduo
{
namespace net
{
class Timer;
///
/// An opaque identifier, for canceling Timer.
///
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* timer_;
//定时器的序号,每个定时器都有唯一的一个编号
int64_t sequence_;
};
}
}
#endif // MUDUO_NET_TIMERID_H
2.Timer类
数据成员:
const TimerCallback callback_:定时器回调函数,在定时器超时时被调用,定义在Callbacks.h
Timestamp expiration_:下一次的超时时刻
const double interval_:超时时间间隔,如果是一次性定时器,该值为0
const bool repeat_:是否重复,若为false,表示一次性定时器
const int64_t sequence_:定时器序号,每个定时器都有唯一的一个编号
static AtomicInt64 s_numCreated_:定时器计数,当前已经创建的定时器数量
成员函数:
Timer(const TimerCallback& cb, Timestamp when, double interval):构造函数
void run() const:调用定时器回调函数callback_
Timestamp expiration() const:返回下一次的超时时刻expiration_
bool repeat() const:返回repeat_,判断是否是一次性定时器
int64_t sequence() const:返回定时器序号sequence_
void restart:重启定时器
static int64_t numCreated():获取s_numCreated_的值
Timer.h
#ifndef MUDUO_NET_TIMER_H
#define MUDUO_NET_TIMER_H
#include <boost/noncopyable.hpp>
#include <muduo/base/Atomic.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/Callbacks.h>
namespace muduo
{
namespace net
{
///
/// Internal class for timer event.
///
class Timer : boost::noncopyable
{
public:
Timer(const TimerCallback& cb, Timestamp when, double interval)
: callback_(cb),
expiration_(when),
interval_(interval),
repeat_(interval > 0.0),
//原子操作,先加后获取,初始为1
sequence_(s_numCreated_.incrementAndGet())
{ }
//调用定时器回调函数callback_
void run() const
{
callback_();
}
//返回下一次的超时时刻expiration_
Timestamp expiration() const { return expiration_; }
//返回repeat_,判断是否是一次性定时器
bool repeat() const { return repeat_; }
//返回定时器序号sequence_
int64_t sequence() const { return sequence_; }
//重启定时器
void restart(Timestamp now);
//获取s_numCreated_的值
static int64_t numCreated() { return s_numCreated_.get(); }
private:
// 定时器回调函数,在定时器超时时被调用,定义在Callbacks.h
const TimerCallback callback_;
// 下一次的超时时刻
Timestamp expiration_;
// 超时时间间隔,如果是一次性定时器,该值为0
const double interval_;
// 是否重复,若为false,表示一次性定时器
const bool repeat_;
// 定时器序号,每个定时器都有唯一的一个编号
const int64_t sequence_;
// 定时器计数,当前已经创建的定时器数量
static AtomicInt64 s_numCreated_;
};
}
}
#endif // MUDUO_NET_TIMER_H
Timer.cc
#include <muduo/net/Timer.h>
using namespace muduo;
using namespace muduo::net;
AtomicInt64 Timer::s_numCreated_;
void Timer::restart(Timestamp now)
{
if (repeat_)
{
// 重新计算下一个超时时刻
//addTime()是定义在Timestamp.h头文件中的全局函数
expiration_ = addTime(now, interval_);
}
else
{
//下一个超时时刻等于一个非法时间
expiration_ = Timestamp::invalid();
}
}
3.TimerQueue类
数据成员:
EventLoop* loop_:定时器所属的EventLoop
const int timerfd_:createTimerfd()所创建的定时器描述符
Channel timerfdChannel_:定时器通道timerfdChannel_
TimerList timers_:按到期时间排序的定时器列表timers_
ActiveTimerSet activeTimers_:按对象地址排序定时器列表activeTimers_
bool callingExpiredTimers_:是否在处理超时的定时器当中
ActiveTimerSet cancelingTimers_:保存被取消的定时器
typedef
typedef std::pair<Timestamp, Timer*> Entry
typedef std::set TimerList
typedef std::pair<Timer*, int64_t> ActiveTimer
typedef std::set ActiveTimerSet
成员函数:
TimerQueue(EventLoop* loop):构造函数,构造函数,当定时器事件到来时,设定定时器通道timerfdChannel_可读事件产生的时候需要回调的函数handleRead(),之后通知定时器通道timerfdChannel_可读,将timerfdChannel_加入到Poller关注
~TimerQueue():析构函数
TimerId addTimer(const TimerCallback& cb,Timestamp when,double interval):增加一个定时器
void cancel(TimerId timerId):取消一个定时器
void addTimerInLoop(Timer* timer):在addTimer()中被调用,添加一个计时器
void cancelInLoop(TimerId timerId):在cancel()中被调用,取消一个计时器
void handleRead():定时器事件到来的时候,可读事件产生,会回调handleRead()函数
std::vector getExpired(Timestamp now):返回所有超时的定时器列表
void reset(const std::vector& expired, Timestamp now):重置超时的定时器
bool insert(Timer* 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:
//构造函数,当定时器事件到来时,设定定时器通道timerfdChannel_可读事件产生的时候需要回调的函数handleRead()
//之后通知定时器通道timerfdChannel_可读,将timerfdChannel_加入到Poller关注
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.
//增加一个定时器
// 一定是线程安全的,可以跨线程调用(可以在其他EventLoop中调用)。通常情况下被其它线程调用。
TimerId addTimer(const TimerCallback& cb,
Timestamp when,
double interval);
//取消一个定时器
void cancel(TimerId timerId);
private:
// FIXME: use unique_ptr<Timer> instead of raw pointers.
// unique_ptr是C++ 11标准的一个独享所有权的智能指针
// 无法得到指向同一对象的两个unique_ptr指针
// 但可以进行移动构造与移动赋值操作,即所有权可以移动到另一个对象(而非拷贝构造)
typedef std::pair<Timestamp, Timer*> Entry;
typedef std::set<Entry> TimerList;
typedef std::pair<Timer*, int64_t> ActiveTimer;
typedef std::set<ActiveTimer> ActiveTimerSet;
// 以下成员函数只可能在其所属的I/O线程中调用,因而不必加锁。
// 服务器性能杀手之一是锁竞争,所以要尽可能少用锁
//在addTimer()中被调用,添加一个计时器
void addTimerInLoop(Timer* timer);
//在cancel()中被调用,取消一个计时器
void cancelInLoop(TimerId timerId);
// called when timerfd alarms
//定时器事件到来的时候,可读事件产生,会回调handleRead()函数
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
EventLoop* loop_;
//createTimerfd()所创建的定时器描述符
const int timerfd_;
//定时器通道timerfdChannel_
Channel timerfdChannel_;
// Timer list sorted by expiration
//按到期时间排序的定时器列表timers_
TimerList timers_;
// for cancel()
// timers_与activeTimers_保存的是相同的数据
// 按对象地址排序定时器列表activeTimers_
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
{
// 创建定时器
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;
}
// 清除定时器,避免一直触发
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";
}
}
// 重置定时器的超时时间
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;
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;
}
}
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));
*/
addTimerInLoop(timer);
return TimerId(timer, timer->sequence());
}
void TimerQueue::cancel(TimerId timerId)
{
/*
loop_->runInLoop(
boost::bind(&TimerQueue::cancelInLoop, this, timerId));
*/
cancelInLoop(timerId);
}
void TimerQueue::addTimerInLoop(Timer* timer)
{
loop_->assertInLoopThread();
// 插入一个定时器,有可能会使得最早到期的定时器发生改变
bool earliestChanged = insert(timer);
if (earliestChanged)
{
// 重置定时器的超时时刻(timerfd_settime)
resetTimerfd(timerfd_, timer->expiration());
}
}
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,如果用了unique_ptr,这里就不需要手动删除了
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); // 清除该事件,避免一直触发
// 获取该时刻之前所有的定时器列表(即超时定时器列表)
std::vector<Entry> expired = getExpired(now);
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);
}
// rvo
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));
// 返回第一个未到期的Timer的迭代器
// lower_bound的含义是返回第一个值>=sentry的元素的iterator
// 即*end >= sentry,从而end->first > now
TimerList::iterator end = timers_.lower_bound(sentry);
assert(end == timers_.end() || now < end->first);
// 将到期的定时器插入到expired中
std::copy(timers_.begin(), end, back_inserter(expired));
// 从timers_中移除到期的定时器
timers_.erase(timers_.begin(), end);
// 从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;
}
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())
{
// 重置定时器的超时时刻(timerfd_settime)
resetTimerfd(timerfd_, nextExpire);
}
}
bool TimerQueue::insert(Timer* timer)
{
loop_->assertInLoopThread();
assert(timers_.size() == activeTimers_.size());
// 最早到期时间是否改变
bool earliestChanged = false;
Timestamp when = timer->expiration();
TimerList::iterator it = timers_.begin();
// 如果timers_为空或者when小于timers_中的最早到期时间
if (it == timers_.end() || when < it->first)
{
earliestChanged = true;
}
{
// 插入到timers_中
std::pair<TimerList::iterator, bool> result
= timers_.insert(Entry(when, timer));
assert(result.second); (void)result;
}
{
// 插入到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;
}