1. 程式人生 > >redis 事件處理

redis 事件處理

事件處理其實很簡單,下面這個函式

403 //主函式
404 void aeMain(aeEventLoop *eventLoop) {
405     eventLoop->stop = 0;
406     while (!eventLoop->stop) {
407         if (eventLoop->beforesleep != NULL)
408             eventLoop->beforesleep(eventLoop);
409         aeProcessEvents(eventLoop, AE_ALL_EVENTS);
410     }
411 }

就是不斷的迴圈,呼叫 aeProcessEvents.


aeProcessEvents:

這個函式就是處理事件的,包括了時間事件和檔案事件。

int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
    int processed = 0, numevents;

    /* Nothing to do? return ASAP */
    if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0;

    /* Note that we want call select() even if there are no
     * file events to process as long as we want to process time
     * events, in order to sleep until the next time event is ready
     * to fire. */
    //即使沒有檔案事件,只要有時間事件(並且 AE_DONT_WAIT), 也計算等待時間
    if (eventLoop->maxfd != -1 ||
        ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {
        int j;
        aeTimeEvent *shortest = NULL;
        struct timeval tv, *tvp;
        //查詢和現在最近的事件
        if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT))
            shortest = aeSearchNearestTimer(eventLoop);
        if (shortest) {
            //最早觸發事件的時間
            long now_sec, now_ms;

            /* Calculate the time missing for the nearest
             * timer to fire. */
            aeGetTime(&now_sec, &now_ms);
            tvp = &tv;
            tvp->tv_sec = shortest->when_sec - now_sec;
            //計算時間差值,微妙不夠,從秒這裡拿1
            if (shortest->when_ms < now_ms) {
                tvp->tv_usec = ((shortest->when_ms+1000) - now_ms)*1000;
                tvp->tv_sec --;
            } else {
                tvp->tv_usec = (shortest->when_ms - now_ms)*1000;
            }
            //最早觸發時間已經過了,那就不需要等了
            if (tvp->tv_sec < 0) tvp->tv_sec = 0;
            if (tvp->tv_usec < 0) tvp->tv_usec = 0;
        } else {
            /* If we have to check for events but need to return
             * ASAP because of AE_DONT_WAIT we need to se the timeout
             * to zero */
            if (flags & AE_DONT_WAIT) {
                tv.tv_sec = tv.tv_usec = 0;
                tvp = &tv;
            } else {
                /* Otherwise we can block */
                tvp = NULL; /* wait forever */
            }
        }
        //從上面計算的到在這裡阻塞的時間
        numevents = aeApiPoll(eventLoop, tvp);
        for (j = 0; j < numevents; j++) {
            aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
            int mask = eventLoop->fired[j].mask;
            int fd = eventLoop->fired[j].fd;
            int rfired = 0;

            /* note the fe->mask & mask & ... code: maybe an already processed
             * event removed an element that fired and we still didn't
             * processed, so we check if the event is still valid. */
            if (fe->mask & mask & AE_READABLE) {
                rfired = 1;
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
            }
            if (fe->mask & mask & AE_WRITABLE) {
                if (!rfired || fe->wfileProc != fe->rfileProc)
                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);
            }
            processed++;
        }
    }
    /* Check time events */
    if (flags & AE_TIME_EVENTS)
        processed += processTimeEvents(eventLoop);

    return processed; /* return the number of processed file/time events */
}

我們可以把主程式當作是一個開車的父親,時間事件是接女兒放學,檔案事件是去車站接客人賺錢。

那麼AE_DONT_WAIT可以理解為不能在車站停靠。

1 首先決定是否需要計算在車站等待時間:

           if (eventLoop->maxfd != -1 ||
                 ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) 

           需要滿足下面任何一個條件:

            一   有客人會出現

            二  今天要去接女兒  並且 車站允許停靠車子

2 計算女兒放學時間:

           如果今天上學,

                    那麼就得到放學時間,和當前時間比較,如果還沒有到,那麼再等等,到了就不要等了

           如果不上學,那麼就只要處理乘客,如果車站不讓聽,馬上走,如果給停,一定等待乘客出現

3 把乘客送過去(如果有)

4 送女兒回家(如果上學)