memcached 每个处理子线程有一个event结构,各个子线程处理分配给该线程的请求
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 */
uint8_t item_lock_type; /* use fine-grained or global item lock */
} LIBEVENT_THREAD;
1、进程启动时,main调用thread_init()初始化线程数据
for (i = 0; i < nthreads; i++) {
int fds[2];
if (pipe(fds)) {
perror("Can't create notify pipe");
exit(1);
}
//主线程接收到新的连接请求后,把连接请求加入thread的到new_conn_queue队列中,notify_receive_fd用来通知处理线程
threads[i].notify_receive_fd = fds[0];
threads[i].notify_send_fd = fds[1];
setup_thread(&threads[i]);
/* Reserve three fds for the libevent base, and two for the pipe */
stats.reserved_fds += 5;
}
2、建立线程
setup_thread()
/* Listen for notifications from other threads */
//设置notify_receive_fd的回调函数thread_libevent_process
//监听notify_receive_fd,接收来自主线程的通知
event_set(&me->notify_event, me->notify_receive_fd,
EV_READ | EV_PERSIST, thread_libevent_process, me);
event_base_set(me->base, &me->notify_event);
cq_init(me->new_conn_queue);//初始化连接队列
3、启动线程
static void *worker_libevent(void *arg) {
LIBEVENT_THREAD *me = arg;
/* Any per-thread setup can happen here; thread_init() will block until
* all threads have finished initializing.
*/
/* set an indexable thread-specific memory item for the lock type.
* this could be unnecessary if we pass the conn *c struct through
* all item_lock calls...
*/
me->item_lock_type = ITEM_LOCK_GRANULAR;
pthread_setspecific(item_lock_type_key, &me->item_lock_type);
register_thread_initialized();
event_base_loop(me->base, 0);
return NULL;
}
4、当有新的连接到来时,主线程写入管道通知处理线程。处理线程接收到主线程的通知后,调用回调函数thread_libevent_process。
a)从请求队列中取出连接:
item = cq_pop(me->new_conn_queue);
b)分配新连接
conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
item->read_buffer_size, item->transport, me->base);
c)设置回调函数
event_set(&c->event, sfd, event_flags, event_handler, (void *)c);//设置回调函数event_handler
d)把连接注册到线程的base中
event_base_set(base, &c->event);