TimerQueue Class
源码阅读
@(Linux多线程服务端编程:使用muduoC++网络库读书笔记)
文章目录
TimerQueue Class
封装了基于
timerfd
的计时器,可是它承担什么工作呢?单纯是确定当前的时间吗?超时回调,超时的时候进行什么工作吗?它来帮助
epoll
实现0轮询吗?
TimerQueue Class
涉及两个相关类型:Timer Class
和TimerId Class
:
Timer Class
源码阅读
Timer Class
维护定时器的各种信息:超时时间、触发间隔、触发周期、序列号等。
数据成员
TimerCallback callback_
回调函数,可是这个回调函数,只在
run
里被调用吗?
Timestamp expiration_
到期时间
const double interval_
周期触发间隔
const bool repeat_
是否周期触发,如果
interval_
不为0,repeat_
便为true
。
sequence_
定时器的序列号,似乎是通过一个静态变量
s_numCreated_
递增的。
函数成员
static int64_t numCreated() { return s_numCreated_.get(); }
这是干嘛的?
Timestamp expiration() const { return expiration_; } bool repeat() const { return repeat_; } int64_t sequence() const { return sequence_; }
获取
到期时间
/是否重复
/序列号
void run() const
运行
callback_()
void restart(Timestamp now)
如果是可重复的,就根据
interval
重新设置expiration_
。不然就设置expiration_
为0。
TimerId Class
TimerId Class
是暴露给用户的,通过Timer* timer_
和int64_t sequence_
唯一确定一个定时器。
数据成员
Timer* timer_
Timer Class
对象
int64_t sequence
就是它所保存的
timer_
的Timer::sequence_
函数成员
只有构造函数。
TimerQueue Class
TimerQueue Class
是基于timerfd
实现的定时器功能。使用
M
O
N
O
T
O
N
I
C
MONOTONIC
MONOTONIC时间,即以绝对时间为准,获取从系统启动到现在的时间。
数据成员
EventLoop* loop_
当前
TimerQueue CLass
所属 I / O 线 程 I/O线程 I/O线程。
const int timerfd_
timerfd
句柄,在构造函数中初始化
Channel timerfdChannel_
负责监控
timerfd_
的Channel Class
std::set<std::pair<Timestamp,Timer*>> timers_
以
<到期时间,Timer地址>
排序的红黑树,用于快速找到最先到期的Timer Class
对象,或者根据给定时间找出所有到期的Timer
问题1:set
重定义的排序在哪儿?难道不需要吗?
std::set<std::pair<Timer*,int64_t>> activeTimers_
以
<Timer地址,序列号>
排序的红黑树,用于在执行TimerQueue::cancel()
时,根据TimerID Class
快速查找有无对应的Timer
callingExpiredTimers_
在执行到期定时器的回调函数(
Timer::run
)时为true
,否则为false
。
std::set<std::pair<Timer*,int64_t>> cancelingTimers_
当
callingExpiredTimers_
为true
时,一些定时器到期后会被从activeTimers_
中剔除,但是周期性的定时器会稍后加入avtiveTimers_
中。在定时器不在activeTimers_
的这段时间里,如果要执行TimerQueue::cancelInLoop
是找不到这些定时器的。于是选择将其放入cancelingTimers
中,当执行TimerQueue::reset时
时,这些周期性的
在cancelingTimers_
中的定时器不会被重置。
函数成员
TimerQueue(EventLoop* loop);
初始化相关数据成员,并监视
timerfd_
的读事件,并设置timerfd_
的读回调为TimerQueue::handleRead
。
TimerId addTimer(TimerCallback cb,Timestamp when,double interval);
根据输入的到期回调函数
cb
,到期时间when
,重复间隔interval
创建一个新的Timer Class
对象。同时将其加入timers_
和activeTimers_
中(TimerQueue::addTimerInLoop
)。但是本函数(TimerQueue::addTimer
)可能会在别的线程调用,而timers_
和activeTimers_
没有被锁保护,所以addTimerInLoop
要被注册到EventLoop::pendingFuntors_
中(EventLoop::runInLoop()
)在EventLoop::loop()
的循环中调用,在 I / O I/O I/O线程中执行将新Timer Class
对象添加到timers_
和activeTimers_
中的任务。
void addTimerInLoop(Timer* timer)
执行将
timer
添加到timers_
和activeTimers_
中的任务(``insert) 如果新加入的
timer为第一个
timer或者它的到期时间比当前最早的到期时间还要早,则调整
timerfd的到期时间(
resetTimerfd,其中封装了
timerfd_settime`)。
bool insert(Timer* timer)
将
timer
插入到TimerQueue::timers_
和TimerQueue::activeTimers_
中。注意这里activeTimers_
中pair
的第二项sequence
就是Timer::sequence_
。结合上面提到的activeTimes_
的<Timer*,int64_t>
用于分辨TimerID Class
对象,我们可以知道TimerID::sequence_
就是它所保存的timer_
的Timer::sequence_
。
void handleRead()
读事件被触发,证明
eventfd_
上有事件可读,即有定时器到期,执行删除操作、执行到期回调函数、重设eventfd_
等操作。
1 获取当前时间,获取到当前时间为止所有到期的定时器(getExpired()
)
2 执行到期定时器的到期回调函数Timer::run
3 遍历到期定时器序列,周期性触发且不存在于cancelingTimers_
的重新加入timers_
和activeTimers_
(insert
),其余的删除,并更新eventfd_
的等待时间。(reset
)
std::vector<std::pair<Timestamp, Timer*>> getExpired(Timestamp now)
将到
now
为止的过期事件,从timers_
和activeTimes_
中剔除,并组织成数组返回。
void reset(const std::vector<std::pair<Timestamp, Timer*>>& expired, Timestamp now)
遍历到期定时器序列,周期性触发且不存在于
cancelingTimers_
的重新加入timers_
和activeTimers_
(insert
),其余的删除,并更新eventfd_
的等待时间。
void cancel(TimerId timerId)
从
timers_
和activeTimers_
中剔除timerId
的相关内容。因为这个也必须在 I / O 线 程 I/O线程 I/O线程中进行所以也是向EventLoop::runInLoop
注册了回调(cancelInLoop
)
void cancelInLoop(TimerId timerId)
具体执行剔除操作
如果被剔除的timerId
就存在于activeTimers_
中那直接剔除
不然,并且callingExpiredTimers_
为真,那就保存到cancelingTimers_
中
不然就什么都不做