Redis事件管理(二)

Redis的定时器是自己实现的,不是很复杂。说说具体的实现吧。

定时器的存储维护采用的是普通的单向链表结构,具体节点定义为:

 1 /*时间定时器结构体*/
 2 typedef struct aeTimeEvent
 3 {
 4     long long id; /*定时器的编号*/
 5     long when_sec; /* seconds */
 6     long when_ms; /* milliseconds */
 7     aeTimeProc *timeProc;/*时间到达处理函数*/
 8     aeEventFinalizerProc *finalizerProc;/*删除清理函数*/
 9     void *clientData;/*带外数据*/
10     struct aeTimeEvent *next;/*定时器的存储采用的是链表结构*/
11 } aeTimeEvent;

定时器记录的根节点的位置是在事件管理器中,剩下的就是普通的操作函数了

 1 /*添加定时器事件,参数为时间控制器,定时时间,处理函数,函数参数,清理函数*/
 2 long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
 3         aeTimeProc *proc, void *clientData,
 4         aeEventFinalizerProc *finalizerProc)
 5 {
 6     /*生成ID*/
 7     long long id = eventLoop->timeEventNextId++;
 8     aeTimeEvent *te;
 9
10     te = zmalloc(sizeof(*te));
11     if (te == NULL) return AE_ERR;
12     te->id = id;
13     /*调整时间*/
14     aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms);
15     te->timeProc = proc;
16     te->finalizerProc = finalizerProc;
17     te->clientData = clientData;
18     /*加入时间链表中,所有的时间节点都是在头部插入的,没顺序*/
19     te->next = eventLoop->timeEventHead;
20     eventLoop->timeEventHead = te;
21     return id;
22 }
 1 /*删除时间节点,提供时间点的ID就好,如果没找到就返回错误*/
 2 int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
 3 {
 4     aeTimeEvent *te, *prev = NULL;
 5
 6     te = eventLoop->timeEventHead;
 7     /*循环查找节点,调用清理函数并释放内存*/
 8     while(te)
 9     {
10         if (te->id == id)
11         {
12             if (prev == NULL)
13                 eventLoop->timeEventHead = te->next;
14             else
15                 prev->next = te->next;
16             if (te->finalizerProc)
17                 te->finalizerProc(eventLoop, te->clientData);
18             zfree(te);
19             return AE_OK;
20         }
21         prev = te;
22         te = te->next;
23     }
24     return AE_ERR; /* NO event with the specified ID found */
25 }
 1 /*查找激活时间最短的节点*/
 2 static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
 3 {
 4     aeTimeEvent *te = eventLoop->timeEventHead;
 5     aeTimeEvent *nearest = NULL;
 6
 7     while(te)
 8     {
 9         if (!nearest || te->when_sec < nearest->when_sec || (te->when_sec == nearest->when_sec && te->when_ms < nearest->when_ms))
10             nearest = te;
11         te = te->next;
12     }
13     return nearest;
14 }
 1 /* Process time events 处理时间事件,先执行定时器事件,如果有时间设置过端的情况,会导致整个卡死*/
 2 static int processTimeEvents(aeEventLoop *eventLoop)
 3 {
 4     int processed = 0;
 5     aeTimeEvent *te;
 6     long long maxId;
 7     time_t now = time(NULL);
 8
 9     if (now < eventLoop->lastTime) /*为啥会出现当前时间小于上次激活时间的问题,重新设置了系统时间,当前时间小于了最后的插入时间*/
10     {
11         te = eventLoop->timeEventHead;
12         while(te)
13         {
14             te->when_sec = 0;
15             te = te->next;
16         }
17     }
18     eventLoop->lastTime = now;/*更新最后操作时间*/
19
20     te = eventLoop->timeEventHead;
21     maxId = eventLoop->timeEventNextId-1;
22     /*时间处理,从链表中逐个检查,找到到达时间的定时器后调用处理函数,然后重新从头遍历,当某个定时器的*/
23     while(te)
24     {
25         long now_sec, now_ms;
26         long long id;
27
28         if (te->id > maxId)
29         {
30             te = te->next;
31             continue;
32         }
33         aeGetTime(&now_sec, &now_ms);
34         if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms))
35         {/*当该节点时间到达时,调用时间处理函数,根据函数的返回来决定是否需要删除定时节点*/
36             int retval;
37
38             id = te->id;
39             retval = te->timeProc(eventLoop, id, te->clientData);
40             processed++;
41
42             /*根据函数的返回值来确定是否仍需注册,返回值为下次的激活时间*/
43             if (retval != AE_NOMORE)
44             {
45                 /*返回值不为-1时需要重新注册函数,返回值为下次激活的时间*/
46                 aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
47             }
48             else
49             {
50                 /*删除定时器*/
51                 aeDeleteTimeEvent(eventLoop, id);
52             }
53             /*定时器函数处理完毕之后为了防止漏掉节点,重新从头结点遍历,这个地方要注意,如果定时时间太短,这个地方会造成死循环,不停的处理定时器事件*/
54             te = eventLoop->timeEventHead;
55         }
56         else
57         {
58             te = te->next;
59         }
60     }
61     return processed;
62 }
时间: 2024-10-31 12:40:35

Redis事件管理(二)的相关文章

Redis事件管理(一)

Redis统一的时间管理器,同时管理文件事件和定时器, 这个管理器的定义: #if defined(__APPLE__) #define HAVE_TASKINFO 1 #endif /* Test for backtrace() */ #if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) #define HAVE_BACKTRACE 1 #endif /* Test for polling API */

Redis事件

Redis事件 Redis的ae(Redis用的事件模型库) ae.c Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象. 时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象. 一.文件事件 Redis基于Reactor模式(将消

Redis 内存管理与事件处理

1 Redis内存管理 Redis内存管理相关文件为zmalloc.c/zmalloc.h,其只是对C中内存管理函数做了简单的封装,屏蔽了底层平台的差异,并增加了内存使用情况统计的功能. void *zmalloc(size_t size) {    // 多申请的一部分内存用于存储当前分配了多少自己的内存     void *ptr = malloc(size+PREFIX_SIZE);      if (!ptr) zmalloc_oom_handler(size); #ifdef HAVE

backbone之事件管理

事件模块Backbone.Event在backbone中占十分重要地位,其它模块Model,Collection, View都依赖于它.通过建成Events的方法来实现事件管理,他是Backbone的核心组成部分. 此外,事件模块的所有方法都挂在了全局的Backbone上,如果你的代码中需要用到自定义事件(实现观察者模式),可以直接使用它.以下是各个方法的意义 on 添加自定义事件 off 删除自定义事件 trigger 派发自定义事件 once 添加只执行一次的自定义事件 (内部依赖于_.on

Redis内存管理的基石zmallc.c源码解读(附录):源码结构表

Redis内存管理的基石zmallc.c源码解读(一) Redis内存管理的基石zmallc.c源码解读(二) 前面两篇博文,细致地介绍了zmalloc.c文件的各个函数,不过大家要想深入学习Redis,还需要自己去看源码才是,我梳理了一下zmalloc.c文件的结构,为大家阅读源码提供便利. 全局变量 名称 类型 说明 used_memory static size_t Redis已用内存空间的大小 zmalloc_thread_safe static int 标识是否线程安全 used_me

redis web管理界面工具安装

Redis WEB管理界面工具安装 一.概述 二.文件下载 三.安装过程 一.概述 1.由于redis是基于C/S的方式开发.也就是说,只要满足于redis的客户端通信要求的,都可以作为redis的客户端,进行连接服务端进行管理操作.这里采用的是基于web方式的来管理redis. 2.基于web的方式的优缺点: 2.1.优点: a.在客户端这边不需要多余操作,只需有个浏览器即可 2.2.缺点: a.由于是web方式,因此,需要服务器提供web服务,如果web服务配置不当,易引起安全问题. 3.这

Redis学习系列二之.Net开发环境搭建及基础数据结构String字符串

一.简介 Redis有5种基本数据结构,分别是string.list(列表).hash(字典).set(集合).zset(有序集合),这是必须掌握的5种基本数据结构.注意Redis作为一个键值对缓存系统,其所有的数据结构,都以唯一的key(字符串)作为名称,然后通过key来获取对应的数据. 二..Net开发环境搭建 这个版本,暂时不考虑并发问题,后续的文章会说!第一步:安装StackExchange.Redis包,我用的是2.0.519版本的. 第二步:编写代码,采用扩展方法的链式编程模式+as

ITSM金融行业案例分析:ManageEngine助力IT事件管理

用户概况 易方达基金管理有限公司成立于2001年4月17日,注册资本1.2亿元人民币,旗下设有北京.广州.上海.南京.成都分公司.公司目前兼具公募基金.社保基金.企业年金基金.QDII.专户资产管理业务资格.截至2013年12月31日,易方达旗下管理的各类资产的总规模近2400亿人民币,是国内最具实力.业务品种最全的基金管理公司之一,基金管理规模在全国排名前三的基金公司. 面临问题 目前易方达基金IT部门共有二十多人,管理着多达上百个业务系统,而且这些系统十分复杂,维护工作非常繁重,给IT部门带

几款开源的图形化Redis客户端管理软件

您的评价: 收藏该经验 阅读目录 Redis Desktop Manager Redis Client Redis Studio 原文  http://ourjs.com/detail/555975b9329934463f00000f Redis是一个超精简的基于内存的键值对数据库(key-value),一般对并发有一定要求的应用都用其储存session,乃至整个数据库. 参见: node.js与redis结合使用 . 不过它公自带一个最小化的命令行式的数据库管理工具,有时侯使用起来并不方便.不