Skip to content

Latest commit

 

History

History
34 lines (25 loc) · 2.72 KB

File metadata and controls

34 lines (25 loc) · 2.72 KB

TimerFd

定时器 这一节中,我们提及到TimerEvent的实现。本质上,它是通过epoll()select()中阻塞的超时参数来实现定时任务的。TimerEvent在实际运用中的会有约400us的误差。如果想要精度更好的定时器,则需要使用本节介绍的TimerFd
TimerFd 定义在 eventx/timer_fd.h 中,是基于Linux内核提供的timer_fd实现的。具体的原理可阅读相关文章《Linux fd 系列 — 定时器 timerfd 是什么?

本节通过一个示例来引导大家掌握TimerFd的使用方法。

  1. TimerEvent不同的是TimerFd不属于Loop的一部分,也没有被纳入到框架。要使用它,都需要#include <tbox/eventx/timer_fd.h>
  2. MyModule中分别实列化两个TimerFd对象:oneshot_timer_repeat_timer_
  3. MyModule的初始化列表中对oneshot_timer_repeat_timer_进行构造。注意,它的初始化需要ctx().loop()获取的Loop对象指针;
  4. onInit()中对它们进行初始化,只传一个时间的表示单次触发;传两个时间的表示单次触发之后,还需要重复触发;
  5. onStart()中使能它们。在工程中,不是一定要在onStart()中使能它们,根据业务需要我们也可以在需要的时间再使能它们;
  6. onStop()中关闭它们;
  7. onCleanup()中清理它们;

示例源码
示例工程目录

编译后,执行效果:
我们注意到,它的定时精确误差在5us以内,非常可观。

思考:为什么使用TimerFd的精准度会比TimerEvent高这么多?
猜想:由于TimerFd是基于Linux内核中的timer_fd实现的。在timer_fd触发超时时,内核立即让timer_fd的文件描述符变成可读,鉴于定时器的实时性要求,Linux内核会立即唤醒对应的线程并执行。而基于epoll()select()超时参数的TimerEvent则得不到Linux内核的特殊照顾。当epoll()select()等待超时后,Linux内核只将对应的线程设置为READY状态并排队等待CPU资源,以致于执行的时间点存在较大的误差。

问题:TimerEvent,TimerPool,TimerFd 这三种实现方式如何抉择?
回答:

  • 对于日常对精度要求不太高(如1ms精度可接受)的定时执行场景,可从TimerEventTimerPool中任选一种。如果是对精度要求高,要保证100us以内误差的,使用TimerFd
  • 遇到首次触发与后续触发间隔不一致的,采用TimerFd

[返回主页]