前文回顾
前面讲deadline_timer::async_wait()讲到了epoll_reactor::scheduler_timer(),那时候讲得很模糊,这里稍微展开再讲解一下。首先先回顾下scheduler_timer的源码:
template <typename Time_Traits>
void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
const typename Time_Traits::time_type& time,
typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
{
mutex::scoped_lock lock(mutex_);
if (shutdown_)
{
scheduler_.post_immediate_completion(op, false);
return;
}
bool earliest = queue.enqueue_timer(time, timer, op); // 把定时器添加到deadline_timer_service的timer_queue_成员中
scheduler_.work_started(); // scheduler_的类型是scheduler,即io_service的实现类
if (earliest)
update_timeout();
}
// work_started是scheduler的成员函数
void work_started()
{
++outstanding_work_;
}
本文主要关注第14行到第17行这段代码的逻辑。这段逻辑乍看之下十分的晦涩,这逻辑与epoll_reactor的实现逻辑紧密相关,接下来便讲解为何是这样的逻辑。
epoll_reactor大致介绍
epoll_reactor就是一种异步触发器,它的功能概括起来就是能在需要的时候触发scheduler来执行处理函数(这里的处理函数就是外面传进来的回调函数)。这个需要的时候分2种情况,一种是某个描述符变为可读或可写或出错,这个是通过epoll来实现的;另一种是定时器到时间了,这个是通过timerfd来实现的(实际上这个触发条件也是timerfd变为可读,而这个还是得通过前面的epoll来监听)。epoll的相关逻辑在前面的博客已经讲过了,故这里主要讲timerfd的逻辑。
epoll_reactor的定时器逻辑
先从timerfd的相关源码讲起。理所当然的,epoll_reactor里持有一个timerfd的描述符作为它的私有成员,这个描述符名叫timer_fd_。在epoll_reactor的构造函数中会调用epoll_reactor::do_timerfd_create(),这个函数将会完成timer_fd_的初始化,下面是这个函数的源码:
int epoll_reactor::do_timerfd_create()
{
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (fd == -1 && errno == EINVAL)
{
fd =