关于timerfd : http://blog.csdn.net/huntinux/article/details/52095663
private:
const TimerCallback callback_; // 回调函数
Timestamp expiration_; // 过期时间
const double interval_;
const bool repeat_; // 是否重复
const int64_t sequence_; // 当前定时器的编号(基于s_numCreated_)
static AtomicInt64 s_numCreated_; // 记录定时器的个数
调用回调函数
void run() const
{
callback_();
}
重启定时器
void Timer::restart(Timestamp now)
{
if (repeat_)
{
expiration_ = addTime(now, interval_);
}
else
{
expiration_ = Timestamp::invalid();
}
}
///
/// 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_;
int64_t sequence_;
};
比较简单,它继承了boost::less_than_comparable
。关于boost::less_than_comparable
的使用见这里。
muduo使用timerfd
来管理定时器,使得对timer的管理与对socket fd 的管理统一了起来。 (《Linux高性能服务器编程》中提到了统一事件源)
TimerQueue
用来管理Timer,功能包括:
muduo没有使用map
来管理,原因是这么做无法处理两个Timer到期时间相同的情况。为了解决这个问题,muduo对key进行了区分,每个key是一个pair
,这么做就能保证即便到期时间相同也可以区分。
typedef std::pair Entry; // key用pair表示,可以区分到期时间相同的情况
typedef std::set TimerList; // 使用std::set管理Timer,因为只有key没有value,无需使用map
// Timer list sorted by expiration
TimerList timers_;
并且,TimeQueue只在一个线程内使用,所以无需同步控制。
此外,比较重要的一点是,muduo使用一个timerfd管理多个timers_
(set
),该timerfd的超时时间是集合timers_
中的最小超时时间, 即timers_.begin()->second->expiration()
或timers_.begin()->first
,因为set是按照key排序的,第一个定时器timer的超时时间就是最小超时时间。
TimerQueue使用一个Channel来观察timerfd_上的readable事件。Channel是在构造函数设置了回调函数。即,timerfd变为readable时(定时器超时),会调用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();
}
void TimerQueue::handleRead()
{
loop_->assertInLoopThread();
Timestamp now(Timestamp::now());
readTimerfd(timerfd_, now);
// 查询到期的Timer
std::vector expired = getExpired(now);
callingExpiredTimers_ = true;
cancelingTimers_.clear();
// safe to callback outside critical section
for (std::vector ::iterator it = expired.begin();
it != expired.end(); ++it)
{
it->second->run(); // 调用相应的回调函数
}
callingExpiredTimers_ = false;
reset(expired, now);
}
返回值虽然是return-by-value
,但是作者提到了编译器会进行RVO优化,不用担心性能。(详见C++ FAQ)
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); // 返回第一个未到期的Timer
assert(end == timers_.end() || now < end->first);
std::copy(timers_.begin(), end, back_inserter(expired)); // 将所有到期的Timer通过back_inserter放到容器expired中
timers_.erase(timers_.begin(), end); // 删除已经到期的Timer
for (std::vector ::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;
}