標籤:建立 預設 不同 iat not ica zha 而且 簡單
這篇文章是對上篇文章的一個補充,主要環繞下面兩點展開。one-connection-per-thread的實現方式以及線程池中epoll的使用。
one-connection-per-thread
依據scheduler_functions的模板,我們也能夠列出one-connection-per-thread方式的幾個關鍵函數。
static scheduler_functions con_per_functions={ max_connection+1, // max_threadsNULL,NULL,NULL, // initInit_new_connection_handler_thread, // init_new_connection_threadcreate_thread_to_handle_connection, // add_connectionNULL, // thd_wait_beginNULL, // thd_wait_endNULL, // post_kill_notificationone_thread_per_connection_end, // end_threadNULL // end};
1.init_new_connection_handler_thread
這個介面比較簡單,主要是調用pthread_detach。將線程設定為detach狀態,線程結束後自己主動釋放全部資源。
2.create_thread_to_handle_connection
這個介面是處理新串連的介面,對於線程池而言,會從thread_id%group_size相應的group中擷取一個線程來處理,而one-connection-per-thread方式則會推斷是否有thread_cache能夠使用,假設沒有則建立線程來處理。詳細邏輯例如以下:
(1).推斷緩衝的線程數是否使用完(比較blocked_pthread_count 和wake_pthread大小)
(2).若還有緩衝線程,將thd增加waiting_thd_list的隊列,喚醒一個等待COND_thread_cache的線程
(3).若沒有。建立一個新的線程處理,線程的入口函數是do_handle_one_connection
(4).調用add_global_thread增加thd數組。
3.do_handle_one_connection
這個介面被create_thread_to_handle_connection調用,處理請求的主要實現介面。
(1).迴圈調用do_command。從socket中讀取網路包,而且解析運行。
(2). 當遠程client發送關閉串連COMMAND(比方COM_QUIT,COM_SHUTDOWN)時,退出迴圈
(3).調用close_connection關閉串連(thd->disconnect());
(4).調用one_thread_per_connection_end函數,確認能否夠複用線程
(5).依據返回結果,確定退出背景工作執行緒還是繼續迴圈運行命令。
4.one_thread_per_connection_end
推斷能否夠複用線程(thread_cache)的主要函數,邏輯例如以下:
(1).調用remove_global_thread。移除線程相應的thd執行個體
(2).調用block_until_new_connection推斷能否夠重用thread
(3).推斷緩衝的線程是否超過閥值,若沒有,則blocked_pthread_count++;
(4).堵塞等待條件變數COND_thread_cache
(5).被喚醒後,表示有新的thd須要重用線程,將thd從waiting_thd_list中移除,使用thd初始化線程的thd->thread_stack
(6).調用add_global_thread增加thd數組。
(7).假設能夠重用,返回false,否則返回ture
線程池與epoll
在引入線程池之前,server層僅僅有一個監聽線程。負責監聽mysqlport和本地unixsocket的請求。對於每一個新的串連,都會分配一個獨立線程來處理,因此監聽線程的任務比較輕鬆。mysql通過poll或select方式來實現IO的多工。引入線程池後。除了server層的監聽線程,每一個group都有一個監聽線程負責監聽group內的全部串連socket的串連請求,背景工作執行緒不負責監聽,僅僅處理請求。對於overscribe為1000的線程池設定。每一個監聽線程須要監聽1000個socket的請求。監聽線程採用epoll方式來實現監聽。
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。
- port監聽線程監聽到請求後,建立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
(7)port監聽線程
main->mysqld_main->handle_connections_sockets->poll
one-connection-per-thread函數調用關係
(1) 背景工作執行緒等待請求
handle_one_connection->do_handle_one_connection->do_command->
my_net_read->net_read_packet->net_read_packet_header->net_read_raw_loop->
vio_read->vio_socket_io_wait->vio_io_wait->poll
備忘:與線程池的背景工作執行緒有監聽線程協助其監聽請求不同,one-connection-per-thread方式的背景工作執行緒在空暇時。會調用poll堵塞等待網路包過來;
而線程池的背景工作執行緒僅僅須要專心處理請求就可以,所以使用也更充分。
(2)port監聽線程
與線程池的(7)同樣
參考文檔
http://www.cnblogs.com/Anker/p/3265058.html
http://blog.csdn.net/zhanglu5227/article/details/7960677
MySQL具體解釋(8)----------MySQL線程池總結(二)