memcached是一个基于libevent的实现
用于监听连接
他还创建了N个工作线程,用于完成具体的业务
每个工作线程也是event_base_loop的,每个线程处理若干个连接。这个连接时主线程的main_base在accept后接入的
threads[i]记录的是工作线程的一些信息
thread_init里调的setup_thread(&threads[i])完成工作线程的libevent的相关初始化
可知,工作线程监听了发往自己的管道信息,只监听读事件,EV_PERSIST保证没有读完会继续读,这里基本就是主线程给工作线程发
知,工作线程管理了自己的连接队列
worker_libevent是线程函数
在worker_libevent里event_base_loop(me->base, 0)知,work线程开始自己的事件循环。
刚开始时,只有notify_receive_fd这个管道在work线程上
接下来通过server_sockets->server_socket函数创建监听套接字,可以创建unix域,tcp或udp套接字
在server_socket里
只在多网卡下,对每个网口都要监听
将监听端口绑在main_base上,就是主线程上的
最后event_base_loop(main_base, 0)开始主线程的事件循环。
事件回调函数event_handler是监听和服务的都用该函数,里面调了drive_machine(c);
很明显是一个状态机,
一个新的连接接入是到这里
然后将新的连接push入线程的新连接队列里
只读了一个字节,表示处理一个连接,如有多个连接,下次循环会继续触发来处理连接
在主线程创建了一个
main_base = event_init();
...
event_base_loop(main_base, 0)
用于监听连接
他还创建了N个工作线程,用于完成具体的业务
每个工作线程也是event_base_loop的,每个线程处理若干个连接。这个连接时主线程的main_base在accept后接入的
在thread_init(settings.num_threads, main_base)里对主线程和工作线程进行一些初始化工作
dispatcher_thread.base = main_base;
dispatcher_thread.thread_id = pthread_self();
全局变量dispatcher_thread记录了主线程的
threads[i]记录的是工作线程的一些信息
pipe(fds)
...
threads[i].notify_receive_fd = fds[0];
threads[i].notify_send_fd = fds[1];
只是主线程和某个工作线程通信的管道
thread_init里调的setup_thread(&threads[i])完成工作线程的libevent的相关初始化
me->base = event_init();
可知,工作线程也有自己的事件循环
event_set(&me->notify_event, me->notify_receive_fd,
EV_READ | EV_PERSIST, thread_libevent_process, me);
可知,工作线程监听了发往自己的管道信息,只监听读事件,EV_PERSIST保证没有读完会继续读,这里基本就是主线程给工作线程发
me->new_conn_queue = malloc(sizeof(struct conn_queue));
知,工作线程管理了自己的连接队列
初始化完线程后,就开始创建工作者线程。
create_worker(worker_libevent, &threads[i])
worker_libevent是线程函数
在worker_libevent里event_base_loop(me->base, 0)知,work线程开始自己的事件循环。
刚开始时,只有notify_receive_fd这个管道在work线程上
接下来通过server_sockets->server_socket函数创建监听套接字,可以创建unix域,tcp或udp套接字
在server_socket里
error= getaddrinfo(interface, port_buf, &hints, &ai);
...
for (next= ai; next; next= next->ai_next)
{
...
}
只在多网卡下,对每个网口都要监听
conn_new(sfd, conn_listening,EV_READ | EV_PERSIST, 1,transport, main_base)
将监听端口绑在main_base上,就是主线程上的
最后event_base_loop(main_base, 0)开始主线程的事件循环。
事件回调函数event_handler是监听和服务的都用该函数,里面调了drive_machine(c);
很明显是一个状态机,
一个新的连接接入是到这里
case conn_listening:
这里
dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST, DATA_BUFFER_SIZE, tcp_transport)
将新连接分配到一个work线程上去。
dispatch_conn_new里先是选取一个
CQ_ITEM *item = cqi_new();
...
LIBEVENT_THREAD *thread = threads + tid;
然后将新的连接push入线程的新连接队列里
cq_push(thread->new_conn_queue, item);
最后通过管道向该线程发送一个通知
write(thread->notify_send_fd, "", 1)
work线程在thread_libevent_process里处理管道来的通知
只读了一个字节,表示处理一个连接,如有多个连接,下次循环会继续触发来处理连接
read(fd, buf, 1)
通过cq_pop(me->new_conn_queue)弹出新连接,然后通过conn_new函数把连接绑定到work线程上
conn_new(item->sfd, item->init_state, item->event_flags,
item->read_buffer_size, item->transport, me->base)