一、接口
1、创建定时器 timerfd_create
返回值:返回定时器文件描述符。原理:每隔一个超时时间系统会给描述符写入一个8字节数据代表已经超时几次。
clockid:
CLOCK_REALTIME:以系统时间作为基准值(若改变系统时间就会不准确)
CLOCK_MONOTONIC:系统启动时间进行递增的基准值(准确)
flags:0代表阻塞操作,TFD_NONBLOCK非阻塞操作。
2、设置超时时间 timerfd_settime
fd:timerfd_create 返回值
flags:0表示相对时间
struct itimerspec:
new value:这次设置的超时时间。
old value:用于保存上次的超时时间
二、设计时间轮定时器
1、模型
2、代码实现
定时任务类
要有定时任务的id,超时时间,定时任务如果要被析构里面一定要有执行的任务和删除在时间轮里面的位置。
时间轮类
时间轮里面要有 tick 指针,容量(最大延迟时间),二维数组的时间轴(因为一个时间点可能有多个任务)和用 id 来找定时任务的哈希表(注意存放的是定时任务的 weak_ptr,因为要配合 shared_ptr 使用)
(1)添加定时任务
先初始化一个定时任务,添加定时任务的删除函数,然后放入哈希表进行管理,还要放入时间轮
(2)刷新定时任务
刷新定时任务的思路就是多开一个 shared_ptr 指向对应的任务(本质是一个 shared_ptr 指向另一个 shared_ptr,但是最终两者指向的资源就是同一个定时任务,如果全都是一级 shared_ptr 指向同一个定时任务,会在析构时产生问题),最后把新的 shared_ptr 放入时间轮。
(3)取消定时任务
就是调用定时任务的接口,把定时任务里面的 cancled 字段设置成 true,最后在调用定时任务的析构时就可以不调用 _task 任务。
(4)运行任务
每次让 tick 指针向后走一步,然后调用 vector 里面的 clear() 接口,让数组中的定时任务调用析构函数完成任务的调用和时间轮清空。
clear 接口介绍:
vector中存储了对象的指针,调用clear后,并不会调用这些指针所指对象析构函数,因此要在clear之前调用delete
vector存储的是对象,调用clear后,自建类型的对象(int之类的)直接删除,若是外部类型,则调用析构函数。
3、测试
4、设计思路
目标:对于超时连接进行释放。
(1)定义一个类,类实例化一个定时任务对象,对象的析构函数里面存超时任务(即销毁连接)
(2)用 shared_ptr 管理上面的类,每次连接活跃后,类构造一个对象放入时间轮,shared_ptr 引用计数++(相当于刷新了任务),tick 走过销毁一个 shared_ptr,引用计数--,引用计数减到0所管理的对象就会被销毁,调用析构函数执行超时任务。