zoukankan      html  css  js  c++  java
  • memcached线程模型

    直接上图:

    memcached使用多线程模型,一个master线程,多个worker线程,master和worker通过管道实现通信。

    每个worker线程有一个队列,队列元素为CQ_ITEM。

    typedef struct {
        pthread_t thread_id;        /* unique ID of this thread */
        struct event_base *base;    /* libevent handle this thread uses */
        struct event notify_event;  /* listen event for notify pipe */
        int notify_receive_fd;      /* receiving end of notify pipe */
        int notify_send_fd;         /* sending end of notify pipe */
        struct thread_stats stats;  /* Stats generated by this thread */
        struct conn_queue *new_conn_queue; /* queue of new connections to handle */
        cache_t *suffix_cache;      /* suffix cache */
        logger *l;                  /* logger buffer */
        void *lru_bump_buf;         /* async LRU bump buffer */
    } LIBEVENT_THREAD;
    
    /* An item in the connection queue. */
    typedef struct conn_queue_item CQ_ITEM;
    struct conn_queue_item {
        int               sfd;
        enum conn_states  init_state;
        int               event_flags;
        int               read_buffer_size;
        enum network_transport     transport;
        conn *c;
        CQ_ITEM          *next;
    };
    
    /* A connection queue. */
    typedef struct conn_queue CQ;
    struct conn_queue {
        CQ_ITEM *head;
        CQ_ITEM *tail;
        pthread_mutex_t lock;
    };

    memcached使用libevent实现事件监听,master和worker各有一个event_base。

    起初,master负责监听连接的到来,worker线程负责监听管道的读事件。

    当有一个连接到来,master线程accept该连接,并将conn_fd封装成一个CQ_ITEM对象放入一个worker线程的队列中,同时向管道写入数据触发管道读事件。

    对应worker线程执行管道读事件的回调函数thread_libevent_process:

    /*
     * Processes an incoming "handle a new connection" item. This is called when
     * input arrives on the libevent wakeup pipe.
     */
    static void thread_libevent_process(int fd, short which, void *arg) {
        LIBEVENT_THREAD *me = arg;
        CQ_ITEM *item;
        char buf[1];
        unsigned int timeout_fd;
    
        if (read(fd, buf, 1) != 1) {
            if (settings.verbose > 0)
                fprintf(stderr, "Can't read from libevent pipe
    ");
            return;
        }
    
        switch (buf[0]) {
        case 'c':
            item = cq_pop(me->new_conn_queue);
    
            if (NULL != item) {
                conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
                                   item->read_buffer_size, item->transport,
                                   me->base);
                if (c == NULL) {
                    if (IS_UDP(item->transport)) {
                        fprintf(stderr, "Can't listen for events on UDP socket
    ");
                        exit(1);
                    } else {
                        if (settings.verbose > 0) {
                            fprintf(stderr, "Can't listen for events on fd %d
    ",
                                item->sfd);
                        }
                        close(item->sfd);
                    }
                } else {
                    c->thread = me;
                }
                cqi_free(item);
            }
            break;
        case 'r':
            item = cq_pop(me->new_conn_queue);
    
            if (NULL != item) {
                conn_worker_readd(item->c);
                cqi_free(item);
            }
            break;
        /* we were told to pause and report in */
        case 'p':
            register_thread_initialized();
            break;
        /* a client socket timed out */
        case 't':
            if (read(fd, &timeout_fd, sizeof(timeout_fd)) != sizeof(timeout_fd)) {
                if (settings.verbose > 0)
                    fprintf(stderr, "Can't read timeout fd from libevent pipe
    ");
                return;
            }
            conn_close_idle(conns[timeout_fd]);
            break;
        }
    }

    在conn_new中,将conn_fd的读事件添加进自己的event_base中。

    至此,worker线程开始监听连接上的I/O事件。

    参考资料:

    Memcached源码分析之线程模型

  • 相关阅读:
    指针
    使用函数
    数组,切片和字典
    CUDA 进阶学习
    makefile 常用函数
    内存(RAM或ROM)和FLASH存储的真正区别总结
    射频,系带,调制解调器
    固态激光雷达
    毫米波雷达
    对比感知技术的硬件或者算法的关键技术指标
  • 原文地址:https://www.cnblogs.com/gattaca/p/6929361.html
Copyright © 2011-2022 走看看