请选择 进入手机版 | 继续访问电脑版

skynet源码分析之定时器skynet_timer.c

[复制链接]
盛夏丨光年丶 发表于 2021-1-1 17:45:54 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
skynet自带定时器功能skynet-src/skynet_timer.c,在skynet启动时会创建一个线程专门跑定时器。每帧(0.0025秒/帧)调用skynet_updatetime()
  1. 1 // skynet-src/skynet_start.c 2  3 create_thread(&pid[1], thread_timer, m); 4  5 static void * 6 thread_timer(void *p) { 7     struct monitor * m = p; 8     skynet_initthread(THREAD_TIMER); 9     for (;;) {10         skynet_updatetime();11         CHECK_ABORT12         wakeup(m,m->count-1);13         usleep(2500);  //2500微妙=0.0025秒14         if (SIG) {15             signal_hup();16             SIG = 0;17         }18     }19     ...20 }
复制代码
1. 设计思想

skynet的设计思想参考Linux内核动态定时器的机制,参考Linux动态内审定时器先容http://www.cnblogs.com/leaven/archive/2010/08/19/1803382.html,

 
在skynet里,时间精度是0.01秒,这对于游戏服务器来说已经足够了,界说1滴答=0.01秒,1秒=100滴答。其核心思想是:每个定时器设置一个到期的滴答数,与当前系统的滴答数(启动时是0,然后1滴答1滴答往后跳)比力差值,如果差值interval比力小(0time;21     add_node(T,node);22 23     SPIN_UNLOCK(T);24 }25 26 static void27 add_node(struct timer *T,struct timer_node *node) {28     uint32_t time=node->expire;29     uint32_t current_time=T->time;30         31     if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) {32         link(&T->near[time&TIME_NEAR_MASK],node);33     } else {34         int i;35         uint32_t mask=TIME_NEAR near中触发到期的定时器链表,near数组里每一项的链表中的所有节点的到期滴答数是相同的。
调用dispatch_list举行分发,通过current+1获取timer_event数据(第18行),然后给event->handle push一条消息表现触发定时器(第25行)
  1. 1 // skynet-src/skynet_timer.c 2 static inline void 3 timer_execute(struct timer *T) { 4     int idx = T->time & TIME_NEAR_MASK; 5          6     while (T->near[idx].head.next) { 7         struct timer_node *current = link_clear(&T->near[idx]); 8         SPIN_UNLOCK(T); 9         // dispatch_list don't need lock T10         dispatch_list(current);11         SPIN_LOCK(T);12     }13 }14 15 static inline void16 dispatch_list(struct timer_node *current) {17     do {18         struct timer_event * event = (struct timer_event *)(current+1);19         struct skynet_message message;20         message.source = 0;21         message.session = event->session;22         message.data = NULL;23         message.sz = (size_t)PTYPE_RESPONSE handle, &message);26                27        struct timer_node * temp = current;28        current=current->next;29        skynet_free(temp);      30     } while (current);31 }
复制代码
每帧除了触发定时器外,还需重新分配定时器所在区间(timer_shift),因为T->near里生存即将触发的定时器,所以每TIME_NEAR-1(2^8-1)个滴答数才有大概需要分配(第22行)。否则,分配T->t中某个等级即可。
当T->time的第8位不全为0时,不需要分配,所以每2^8个滴答数才有需要分配一次;
当T->time的第9-14位不全为0时,重新分配T[0]等级,每2^8个滴答数分配一次,idx从1开始,每次分配+1;
当T->time的第15-20位不全为0时,重新分配T[1]等级,每2^(8+6)个滴答数分配一次,idx从1开始,每次分配+1;
当T->time的第21-26位不全为0时,重新分配T[2]等级,每2^(8+6+6)个滴答数分配一次,idx从1开始,每次分配+1;
当T->time的第27-32位不全为0时,重新分配T[3]等级,每2^(8+6+6+6)个滴答数分配一次,idx从1开始,每次分配+1;
即等级越大的定时器越遥远,越不关注,需要重新分配的次数也就越少。
  1. 1 // skynet-src/skynet_timer.c 2 static void 3 move_list(struct timer *T, int level, int idx) { 4     struct timer_node *current = link_clear(&T->t[level][idx]); 5     while (current) { 6         struct timer_node *temp=current->next; 7         add_node(T,current); 8         current=temp; 9     }10 }11 12 static void13 timer_shift(struct timer *T) {14     int mask = TIME_NEAR;15     uint32_t ct = ++T->time;16     if (ct == 0) {17         move_list(T, 3, 0);18     } else {19         uint32_t time = ct >> TIME_NEAR_SHIFT;20         int i=0;21 22         while ((ct & (mask-1))==0) {23             int idx=time & TIME_LEVEL_MASK;24             if (idx!=0) {25                 move_list(T, i, idx);26                 break;                          27             }28             mask = TIME_LEVEL_SHIFT;30             ++i;31         }32     }33 }
复制代码
3. 如何使用

在C层通过skynet_timeout创建一个定时器
在Lua层通过skynet.timeout创建一个定时器,好比,skynet.timeout(200, f),即颠末200个滴答数(2秒钟)后触发回调函数f。
  1.  
复制代码
 

来源:https://blog.csdn.net/Linuxhus/article/details/112032698
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )