线程池
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池相关的知识,希望对你有一定的参考价值。
数据结构
connection_t
- //sql/threadpool_unix.cc
- 代表客户的连接,包含了客户端连接的所有参数。
thread_group_t
- sql/threadpool_unix.cc 中
代表线程池中的一个分组。
worker_thread_t
- sql/threadpool_unix.cc 中
代表一个worker线程或者一个listener线程。
初始化
- 入口函数 sql/mysqld.cc中的main函数。
包括tp_init函数对线程池进行初始化,然后调用handle_connections_sockets函数循环处理新来的连接。
添加连接到线程池
在handle_connections_sockets中处理,监听端口3306。
//sql/threadpool_unix.cc
void tp_add_connectioin(THD *thd);
static void queue_put(thread_group_t *thread_group, connection_t *connection);//将连接加入到任务队列中,
//让线程池分组中的worker线程去处理。
worker 线程
处理任务队列中待处理的任务。
static void *worker_main(void para); //包括初始化、循环处理任务和线程推出。
- 循环处理过程
- get_event()获取待处理任务。
- handle_event()函数处理任务。
- 处理时,先登录验证,然后将网络套接字加入到poll中,以便监听该连接的后续命令;
对于已登录的连接,读取网络数据,并执行过来的命令。
get_event函数
功能:负责从任务队列获取一个任务,返回给worker线程处理。
//sql/threadpool_unix.cc
connection_t * get_event(worker_thread_t *current_thread, thread_group_t *thread_group,struct timespec *anstime);
- 过程:
- 死循环开始;
- 判断是否超频,判断线程池是否关闭。
- 没有超频并且有待处理任务,获取返回并转给hand_event()处理。
- 如果没有待处理任务,如果线程池中没有listener线程,将其worker变成listener线程。
- 如果线程池中已有listener线程,此时任务队列中没有待处理任务,worker线程进入休眠状态。
- 休眠之后,等待新的任务到来或者超时而唤醒。
- 唤醒时,如果是listener监听新的任务或者有新的连接,需要worker线程进行处理(重新进入死循环);如果是超时,worker主动推出,使得线程池的线程减少(跳出循环)。
listener线程
- 每一个线程池中都有个单独的listener线程用于监听当前分组的所有网络事件。
//sql/threadpool_unix.cc
static connection_t *listener(worker_thread_t *current_thread,thread_group_t *thread_group);
//循环处理
- 处理过程
- io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, -1);
//监听事件,对epoll_wait()函数的封装。 - 监听到事件时,将事件数统计到线程池的io_event_count中(该变量统计的是这个时间段内监听到的网络事件数,
timer线程使用该数据评估该线程池分组是否处于“停滞”状态。 - listener线程在监听事件后,会检查当前任务队列中是否有任务,如果没有,listener变成worker线程来处理
这些任务;如果有,唤醒或者创建worker处理这些事件。
timer线程
- 功能:检查线程池分组是否处于“停滞”状态以及定时清理掉超时的客户端连接。
//sql/threadpool_unix.cc
static voif *timer_thread(void * para);
void check_stall(thread_group_t *thread_group);//判断是否“停滞”、
- 过程
- timer_thread():
- 开启定时器,等待超时mysql_cond_timedwait(&timer->cond, &timer->mutex,&ts);
- 通过返回值的类型,假如是ETIMEOUT;对每个线程池分组检查是否处于“停滞”状态。
- check_install():
- 如果当前线程池分组中没有listener线程,并且io_event_count =0(即从上一次检查没有听到任何的网络时间),
原因:之前的linstener线程变成了worker线程正在执行一个长查询没有返回。
解决:这时需要唤醒或者创建一个worker线程,该线程处理队列中的剩余任务后会自动变成listener线程。 - 重置io_event_count =0;
- 如果队列中有待处理的任务,并且从上一次检查到本次检查之间没有从任务队列消费任务的任务。
原因:worker线程正在执行长查询,导致任务发生了拥塞。
解决:创建或者唤醒新的worker来分担处理的压力。 - 重置queue_event_count=0。
以上是关于线程池的主要内容,如果未能解决你的问题,请参考以下文章