MySQL的线程池原理学习教程

2019-01-04 19:05:16于丽

Select,poll,epoll都是IO多路复用机制,IO多路复用通过一种机制,可以监听多个fd(描述符),比如socket,一旦某个fd就绪(读就绪或写就绪),能够通知程序进行相应的读写操作。epoll相对于select和poll有了很大的改进,首先epoll通过epoll_ctl函数注册,注册时,将所有fd拷贝进内核,只拷贝一次不需要重复拷贝,而每次调用poll或select时,都需要将fd集合从用户空间拷贝到内核空间(epoll通过epoll_wait进行等待);其次,epoll为每个描述符指定了一个回调函数,当设备就绪时,唤醒等待者,通过回调函数将描述符加入到就绪链表,无需像select,poll方式采用轮询方式;最后select默认只支持1024个fd,epoll则没有限制,具体数字可以参考cat /proc/sys/fs/file-max的设置。epoll贯穿在线程池使用的过程中,下面我就epoll的创建,使用和销毁生命周期来描述epoll在线程中是如何使用的。

线程池初始化,epoll通过epoll_create函数创建epoll文件描述符,实现函数是thread_group_init;
端口监听线程监听到请求后,创建socket,并创建THD和connection对象,放在对应的group队列中;
工作线程获取该connection对象时,若还未登录,则进行登录验证
若socket还未注册到epoll,则调用epoll_ctl进行注册,注册方式是EPOLL_CTL_ADD,并将connection对象放入epoll_event结构体中
若是老连接的请求,仍然需要调用epoll_ctl注册,注册方式是EPOLL_CTL_MOD
group内的监听线程调用epoll_wait来监听注册的fd,epoll是一种同步IO方式,所以会进行等待
请求到来时,获取epoll_event结构体中的connection,放入到group中的队列
线程池销毁时,调用thread_group_close将epoll关闭。
备注:

1.注册在epoll的fd,若请求就绪,则将对应的event放入到events数组,并将该fd的事务类型清空,因此对于老的连接请求,依然需要调用epoll_ctl(pollfd, EPOLL_CTL_MOD, fd, &ev)来注册。

 

线程池函数调用关系

(1)创建epoll

tp_init->thread_group_init->tp_set_threadpool_size->io_poll_create->epoll_create

(2)关闭epoll

tp_end->thread_group_close->thread_group_destroy->close(pollfd)

(3)关联socket描述符

handle_event->start_io->io_poll_associate_fd->io_poll_start_read->epoll_ctl

(4)处理连接请求

handle_event->threadpool_process_request->do_command->dispatch_command->mysql_parse->mysql_execute_command

(5)工作线程空闲时

worker_main->get_event->pthread_cond_timedwait

等待thread_pool_idle_timeout后,退出。

(6)监听epoll

worker_main->get_event->listener->io_poll_wait->epoll_wait