muduo--TimerQueue定时器

传统的Reactor是通过控制select和poll的等待时间来实现定时,libevent中就是这么实现的,现在Linux中提供了timerfd,timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景,采用文件描述符实现定时有利于统一事件源。

主要有几个类-----Timer定时器包含超时回调,TimerId定时器加上一个唯一的ID(用户可见),Timestamp时间戳,TimerQueue管理所有的定时器。(TimerQueue和TimerId是友元关系)

Timer:定时器,具有一个超时时间和超时回调,超时时间由当前时间戳加上一个超时时间生成一个绝对时间,定时器回调函数Timer::run(callback)-TimerCallback。

muduo--TimerQueue定时器_第1张图片

 注:这里可以看到Timer中并没有提供将相对时间和时间戳相加的的操作,这是因为在EventLoop中提供的设置超时时间的函数中已经处理过了。

TimerQueue:定时器队列,用于管理所有的定时器,当定时器超时后执行相应的Timer::run()定时器回调。

数据结构:采用set>,用pair原因在一个时间点可能有多个时间戳TimeStamp超时,而查找只返回一个。通过给timerfd一个超时时间实现超时计时,通过Channel管理timerfd,然后向EventLoop和Poller注册timerfd的可读事件,当timerfd的可读事件就绪表明某一个超时时间到点了,TimerQueue::handleRead()遍历set容器找出那些超时的定时器并执行Time::run()实现超时回调。

那么timerfd如何实现多个定时器超时计时的呢?

每次向set插入一个定时器Timer的时候就比较set的头元素的超时时间,若新插入的超时时间小,则更新timerfd的时间,从而保证timerfd始终是set中最近的一个超时时间,当timerfd可读时,需要遍历容器set,因为可能此时又多个Timer超时,为了复用定时器,每次执行完定时器回调后都要检查定时器是否需要再次定时。这里的关键是采用timerfd实现统一事件源。

 

muduo--TimerQueue定时器_第2张图片

 

加入定时器之后的执行流程如下图:

muduo--TimerQueue定时器_第3张图片

你可能感兴趣的:(linux,C++)