Skynet:定时器原理

本文详细解析了Skynet定时器的工作机制,包括其结构体设计和时间片处理方式。定时器通过比较expire与time的高几位二进制值来决定节点插入的位置,定时器线程每2500微秒更新时间并执行相应操作,如刷新时间片、移动链表等。整个过程确保了定时任务的高效执行。
摘要由CSDN通过智能技术生成

定时器涉及到的结构体为:

struct timer_event {
           //记录每个节点回复消息的信息,存储在节点的后面
    uint32_t handle;        //记录定位服务的编号
    int session;            //记录用于接收消息响应时,定位到是响应哪一条消息,由发送消息的服务生成
};

struct timer_node {
                   //节点
    struct timer_node *next;    //指向下一个节点
    uint32_t expire;            //保存该节点的timer_event消息回复事件的触发时间片为:添加时的时间片加上延时触发的时间
};

struct link_list {
                   //链表
    struct timer_node head;        //头节点,head.next指向第一个节点
    struct timer_node *tail;    //尾节点
};

struct timer {
                               //定时器的信息存储结构
    struct link_list near[TIME_NEAR];    //保存时间片低8位的链表,每次都是从该数组中取链表
    struct link_list t[4][TIME_LEVEL];    //保存时间片高24位的链表,按照0,1,2,3从低位到高位都分别对应6位
    struct spinlock lock;                //锁
    uint32_t time;                        //当前的时间片,单位为1/100秒
    uint32_t starttime;                    //系统的开始实时时间,从UTC1970-1-1 0:0:0开始计时,精确到秒
    uint64_t current;                    //从开始时刻到现在的时长,精确到1/100秒
    uint64_t current_point;                //系统启动时长,精确到1/100秒
};

定时器的原理为:如上图所示,32为位无符号整数time记录时间片分别对应数组near[256]和t[4][64],每次添加节点时(skynet_timer.c文件中的add_node函数):(简单的说:如果expire与time之差小于256则将节点添加到near数组对应元素的链表中,否则从高位往低位依次比较expire的第i个6位二进制的值n与time的第i个6位二进制的值m,哪个不相等则将节点添加到数组t[4-i][n]对应的元素链表中),而下面是从低位往高位进行比较的。

首先检查节点的expire与time的高24位是否相等,相等则将该节点添加到expire低8位值对应数组near的元素的链表中,不相等则进行下一步。
检查expire与time的高18位是否相等,相等则将该节点添加到expire低第9位到第14位对应的6位二进制值对应数组t[0]的元素的链表中,如果不相等则进行下一步。
检查expire与time的高12位是否相等,相等则将该节点添加到expire低第15位到第20位对应的6位二进制值对应数组t[1]的元素的链表中,如果不相等则进行下一步。
检查expire与time的高6位是否相等,相等则将该节点添加到expire低第21位到第26位对应的6位二进制值对应数组t[2]的元素的链表中,如果不相等则进行下一步。
将该节点添加到expire低第27位到第32位对应的6位二进制值对应数组t[3]的元素的链表中
定时器线程每隔2500微秒会调用skynet_timer.c文件中的skynet_updatetime函数刷新时间,函数skynet_updatetime的原理为:将本次执行函数skynet_updatetime到上一次执行函数skynet_updatetime的这段时间间隔划分为以1/100秒为单位的时间片,并对这些时间片中的每个时间片都依次进行取操作(skynet_timer.c文件中的timer_execute函数)、刷新时间片time、移动t[4][64]中的链表操作以及取操作。取操作(timer_execute函数)的原理是将time的低8位值对应的near[256]数组中的链表取出,依次对链表中的所有节点进行消息回复。刷新时间片time、移动t[4][64]中的链表操作(timer_shift函数)的原理是刷新时间片time:

检查time是否溢出,如果溢出则将t[3][0]这个链表取出并依次将该链表中的节点添加(即实现该链表的移动操作),如果time未溢出,则进行下一步。
检查time低8位是否溢出产生进位,没有则结束,有则检查time的低第9位到第14位是否产生溢出,没有则将time的低第9位到第14位对应的值对应数组t[0]中的链表取出,并依次将该链表中的节点添加(即实现该链表的移动操作),如果有溢出,则进行下一步。
检查time低14位是否溢出产生进位,没有则结束,有则检查time的低第15位到第20位是否产生溢出,没有则将time的低第15位到第20位对应的值对应数组t[1]中的链表取出,并依次将该链表中的节点添加(即实现该链表的移动操作),如果有溢出,则进行下一步。
检查time低20位是否溢出产生进位,没有则结束,有则检查time的低第21位到第26位是否产生溢出,没有则将time的低第21位到第26位对应的值对应数组t[2]中的链表取出,并依次将该链表中的节点添加(即实现该链表的移动操作),如果有溢出,则进行下一步。
检查time低26位是否溢出产生进位,没有则结束,有则检查time的低第27位到第32位是否产生溢出,没有则将time的低第27位到第32位对应的值对应数组t[3]中的链表取出,并依次将该链表中的节点添加(即实现该链表的移动操作)。
在skynet_start.c文件这的skynet_start函数调用了skynet_timer.c文件中的skynet_timer_init函数进行定时器初始化

//初始化系统计时
void skynet_timer_init(void) {
   
    TI = timer_create_timer();            //新建一个计时信息结构体
    uint32_t current = 0;
    systime(&TI->starttime, &current);    //获取系统初始化时的UTC时间
    TI->current = current;
    TI->current_point = gettime();    //获得系统启动时的CPU时间
}

//创建一个计时信息结构体
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值