Redis AE模块

来源:互联网 发布:sar成像rd算法 编辑:程序博客网 时间:2024/05/16 11:59

读的源码是2.6.9。

AE模块是一个简单的事件驱动库,是作者为tcl解释器写的事件循环加以修改便于复用的C库。

支持io事件和定时器,看看其中用到的结构吧:

/* State of an event based program */
typedef struct aeEventLoop {
    int maxfd;   // 当前注册的fd最大值,初始值是-1
    int setsize;   // 轮循的最大文件句柄+1
    long long timeEventNextId;  // 下一个定时事件编号
    time_t lastTime;     // 上次轮循的时间
    aeFileEvent *events;   // 存放注册的io事件数组,数组大小为setsize
    aeFiredEvent *fired;  // 已经轮循到的事件,可以说是epoll之后暂存在这个结构里的
    aeTimeEvent *timeEventHead;  // 定时事件链表
    int stop;  // 循环是否停止
    void *apidata;   // 这是epoll/select/kqueue等用到的结构
    aeBeforeSleepProc *beforesleep;  // 事件循环中每次处理事件之前调用
} aeEventLoop;


/* File event structure */
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) */                      
    aeFileProc *rfileProc;                                             
    aeFileProc *wfileProc;                                             
    void *clientData;
} aeFileEvent;


/* Time event structure */
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */                         
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */                                   
    aeTimeProc *timeProc;                                              
    aeEventFinalizerProc *finalizerProc;                               
    void *clientData;                                                  
    struct aeTimeEvent *next;
} aeTimeEvent;


/* A fired event */                                                    
typedef struct aeFiredEvent {
    int fd;                                                            
    int mask;
} aeFiredEvent;

注意到aeFileEvent和aeTimeEvcent中可以往其中放clientData作为处理时的函数,FileEvent可以分别设置读写的handler,TimeEvent还带一个Finalizer用于销毁lientData。


看看其中的API:

// 创建EventLoop结构

aeEventLoop *aeCreateEventLoop(int setsize);

// 销毁
void aeDeleteEventLoop(aeEventLoop *eventLoop);

// 停止
void aeStop(aeEventLoop *eventLoop);

// 注册io事件
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
        aeFileProc *proc, void *clientData);

// 注销注册的io事件

void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);

// 得到fd对应的mask(读,写,或无注册)

int aeGetFileEvents(aeEventLoop *eventLoop, int fd);

// 注册定时事件,注意新的定时事件排在链表前面,id递增,所以在同一次循环中执行的定时事件,越后面注册的越先执行
long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc);

// 注销注册的定时事件

int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);


// 处理事件

int aeProcessEvents(aeEventLoop *eventLoop, int flags);


// 这个接口比较异类,直接等待一个fd事件发生

int aeWait(int fd, int mask, long long milliseconds);


// 经典的事件循环

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS);
    }   
}


// 使用的事件库名称,如"epoll"
char *aeGetApiName(void);


// 设置BeforeSleep回调  
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);


其中比较细节的是aeProcessEvents,flags有几个取值(是个bit set):

0 什么也不做,直接返回

AE_ALL_EVENTS 先处理io事件,再处理定时事件

AE_FILE_EVENTS 只处理io事件

AE_TIME_EVENTS 只处理定时事件

AE_DONT_WAIT 能不sleep就不sleep,没置这个位时,如果没有定时事件,会一直sleep直到io事件发生

这个eventloop和以前看到的eventloop不同之处在于,它sleep的时间(即epoll的时间)不是一个确定值,而是查找最近的定时事件,等到那个定时事件。

在定时回调函数中新注册的定时事件不会在同一次事件循环中被调用,定时回调有返回值:AE_NOMORE(-1)表示要删除定时事件,其它值则会修改定时事件时间值,让它在未来继续执行。

如果让我用C++写这个事件循环,我大概会用优先队列管理定时事件。

原创粉丝点击