线程池

数据结构

connection_t

  1. //sql/threadpool_unix.cc
  2. 代表客户的连接,包含了客户端连接的所有参数。

thread_group_t

  1. sql/threadpool_unix.cc 中
    代表线程池中的一个分组。

worker_thread_t

  1. sql/threadpool_unix.cc 中
    代表一个worker线程或者一个listener线程。

初始化

  1. 入口函数 sql/mysqld.cc中的main函数。
    包括tp_init函数对线程池进行初始化,然后调用handle_connections_sockets函数循环处理新来的连接。

添加连接到线程池

在handle_connections_sockets中处理,监听端口3306。

  1. //sql/threadpool_unix.cc
  2. void tp_add_connectioin(THD *thd);
  3. staticvoid queue_put(thread_group_t*thread_group,connection_t*connection);//将连接加入到任务队列中,
  4. //让线程池分组中的worker线程去处理。

worker 线程

处理任务队列中待处理的任务。

  1. staticvoid*worker_main(void para);//包括初始化、循环处理任务和线程推出。
  • 循环处理过程
  1. get_event()获取待处理任务。
  2. handle_event()函数处理任务。
  3. 处理时,先登录验证,然后将网络套接字加入到poll中,以便监听该连接的后续命令;
    对于已登录的连接,读取网络数据,并执行过来的命令。

get_event函数

功能:负责从任务队列获取一个任务,返回给worker线程处理。

  1. //sql/threadpool_unix.cc
  2. connection_t* get_event(worker_thread_t*current_thread,thread_group_t*thread_group,struct timespec *anstime);
  • 过程:
  1. 死循环开始;
  2. 判断是否超频,判断线程池是否关闭。
  3. 没有超频并且有待处理任务,获取返回并转给hand_event()处理。
  4. 如果没有待处理任务,如果线程池中没有listener线程,将其worker变成listener线程。
  5. 如果线程池中已有listener线程,此时任务队列中没有待处理任务,worker线程进入休眠状态。
  6. 休眠之后,等待新的任务到来或者超时而唤醒。
  7. 唤醒时,如果是listener监听新的任务或者有新的连接,需要worker线程进行处理(重新进入死循环);如果是超时,worker主动推出,使得线程池的线程减少(跳出循环)。

listener线程

  • 每一个线程池中都有个单独的listener线程用于监听当前分组的所有网络事件。
  1. //sql/threadpool_unix.cc
  2. staticconnection_t*listener(worker_thread_t*current_thread,thread_group_t*thread_group);
  3. //循环处理
  • 处理过程
  1. io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, -1);
    //监听事件,对epoll_wait()函数的封装。
  2. 监听到事件时,将事件数统计到线程池的io_event_count中(该变量统计的是这个时间段内监听到的网络事件数,
    timer线程使用该数据评估该线程池分组是否处于“停滞”状态。
  3. listener线程在监听事件后,会检查当前任务队列中是否有任务,如果没有,listener变成worker线程来处理
    这些任务;如果有,唤醒或者创建worker处理这些事件。

timer线程

  • 功能:检查线程池分组是否处于“停滞”状态以及定时清理掉超时的客户端连接。
  1. //sql/threadpool_unix.cc
  2. static voif *timer_thread(void* para);
  3. void check_stall(thread_group_t*thread_group);//判断是否“停滞”、
  • 过程
  1. timer_thread():
  • 开启定时器,等待超时mysql_cond_timedwait(&timer->cond, &timer->mutex,&ts);
  • 通过返回值的类型,假如是ETIMEOUT;对每个线程池分组检查是否处于“停滞”状态。
  1. check_install():
  • 如果当前线程池分组中没有listener线程,并且io_event_count =0(即从上一次检查没有听到任何的网络时间),
    原因:之前的linstener线程变成了worker线程正在执行一个长查询没有返回。
    解决:这时需要唤醒或者创建一个worker线程,该线程处理队列中的剩余任务后会自动变成listener线程。
  • 重置io_event_count =0;
  • 如果队列中有待处理的任务,并且从上一次检查到本次检查之间没有从任务队列消费任务的任务。
    原因:worker线程正在执行长查询,导致任务发生了拥塞。
    解决:创建或者唤醒新的worker来分担处理的压力。
  • 重置queue_event_count=0。





posted @ 2017-05-27 15:32  auyeungcarl  阅读(612)  评论(0编辑  收藏  举报