对应p28
完全理清思路后,感觉实现方式真的很厉害!
基本结构
个人理解
这里我觉得的重点如下:
一.Timer类其实并没有实现定时的功能,只是记录了定时任务的设置参数:
二.核心的定时器实现部分为:
注意,当TimerList为空时,earliestChanged也为true。
核心的定时功能是在TimerQueue::resetTimerfd中调用::timerfd_settime实现的:
三.一个EventLoop对象中有一个TimerQueue对象(组合关系),每个TimerQueue对象中也记录了所属的EventLoop对象。
EventLoop类中:
boost::scoped_ptr<TimerQueue> timerQueue_;
TimerQueue类中:
EventLoop* loop_; // 所属EventLoop,一个TimerQueue对象只属于一个EventLoop对象
四.一个定时器文件描述符timerfd_管理多个timer对象,但是每次只能满足一个timer对象(TimerList中的timer对象按到期时间排序,所以满足的也就是TimerList中的第一个timer对象)。
五.获取超时定时器列表的原因:
所有timer对象都放在TimerList(set集合)中。因为一个timerfd_每次只能满足一个timer对象(TimerList中的timer对象按到期时间排序,所以满足的也就是TimerList中的第一个timer对象)。
但是TimerList中的某些timer对象也有可能到期时间是相同的,所以当timerfd_满足的那个timer对象超时时,还要判断其他timer对象是否也超时了。
六.TimerQueue的构造函数,里面主要完成了这么几件事:
1.调用::timerfd_create创建定时器文件描述符timerfd_。
2.注册IO事件,即创建Channel对象。
3.在构造函数函数体中添加定时器读事件关注,并设置定时器读事件到来时触发的回调函数。
七.TimerQueue中的Channel与TimerQueue是组合关系。
八.TimerId类是外部类,对外可见;Timer类和TimerQueue类是内部类,对外隐藏。
调用顺序
添加定时器
EventLoop::runAt–>TimerQueue::addTimer–>TimerQueue::addTimerInLoop
删除定时器
EventLoop::cancel–>TimerQueue::cancel–>TimerQueue::cancelInLoop
源码
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),
sequence_(s_numCreated_.incrementAndGet())
{
}
void run() const
{
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_; // 超时时间间隔,如果是一次性定时器,该值为0
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_)
{
// 重新计算下一个超时时刻
expiration_ = addTime(now, interval_);
}
else
{
expiration_ = Timestamp::invalid();
}
}
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_;
int64_t sequence_;
};
}
}
#endif // MUDUO_NET_TIMERID_H
TimerQueue.h
// This is an internal header file, you should not include this.
#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.