簡介
在嵌入式系統環境下,由於系統資源和任務的特點,多線程成了實現多任務處理的重要方式.在一些常見的應用環境中,如Web服務器,Email服務器以及數據庫服務器等都具有一個共同點:單位時間內必須處理很多並發的連接請求,但處理時間卻相對較短.傳統多線程方案中我們采用的服務器模型則是一旦接受到請求之後,即創建一個新的線程,由該線程執行任務.任務執行完畢後,線程退出,這就是是"即時創建,即時銷毀"的策略.盡管與創建進程相比,創建線程的時間已經大大的縮短,但是如果提交給線程的任務是執行時間較短,而且執行次數及其頻繁,那麼服務器將處於不停的創建線程,銷毀線程的狀態.
線程池是采用多線程解決方案來提高系統性能的一個最為出色的模型,它通過預創建一定數量的工作線程來對系統進行並發處理,使得系統的運行效率提高.因為線程池能使得系統采用較為輕量的,可控的系統資源實現系統並發處理能力的最大化,所以許多應用軟件都采用了線程池模型.
除此之外,線程是能夠限制創建的進程個數.通常線程池所允許的並發線程具有上界的,如果同時需要並發的線程數超過上界,那麼一部分線程將等待.而傳統方案中,如果同時請求數據為200,那麼最壞情況下,系統可能需要產生200個線程.盡管這不是一個很大的數目,但是也有系統達不到這個要求.
線程池模型有許多種,常見的有三種:任務隊列控制的線程池模型,工作線程控制的線程池模型,主控線程控制的線程池模型.本文將給出一中任務隊列控制的線程池模型的具體實現.
任務隊列控制的線程池模型是通過任務隊列來對線程池進行並發調度,如下圖所示.線程池是由預創建的一個任務隊列和一組工作線程組成,其中任務隊列中存放工作對象.線程池啟動後,工作線程將采用輪詢的方式從任務隊列中獲取任務對象,由於初始化時任務隊列中不存在任務對象,這時的信號量為0,所有的工作線程都處於阻塞狀態.主控線程將任務對象放入任務隊列中,並將信號量加1,這樣信號量就會喚醒一個阻塞中的工作線程(操作系統層面決定喚醒哪個阻塞的工作線程).工作線程喚醒後從任務隊列中獲取一個任務對象並執行該任務,執行完後,工作線程將再次訪問信號量,如果信號信號量大於0,那麼工作線程將繼續從任務隊列中獲取任務對象並執行,知道信號量等於0,這時的工作線程將再次被阻塞.
任務隊列控制的線程模型主要是通過任務隊列上的信號來控制線程池中的線程調度.
線程池的實現
本例程共由5個文件構成:tpool.h,tpool.c,log.c,log.h,testpool.c.其中tpool.h,tpool.c是實現線程池的核心文件,在tpool.h中定義了線程池和工作線程的數據結構及創建線程池和添加工作線程等方法,tpool.c中為具體的實現代碼.log.c,log.h提供了一種記錄文件的生成手段,能在文件中記錄自定義的信息.testpool.c為線程池的測試程序.
該例子由多個源文件組成,編譯命令如下:gcc -g -pthread -o testpool testpool.c tpool.c log.c
下面給出這個例子的源代碼,首先是線程池的定義文件tpool.h:
/*-------------------------------------------------------------------------
* tpool.h – 線程池定義
* -------------------------------------------------------------------------
*/
#ifndef _TPOOL_H_
#define _TPOOL_H_
#include <stdio.h>
#include <pthread.h>
/*工作線程鏈表*/
typedef struct tpool_work
{
void (*handler_routine)(); /*任務函數指針*/
void *arg; /*任務函數參數*/
struct tpool_work *next; /*下一個任務鏈表*/
} tpool_work_t;
/*線程池結構體*/
typedef struct tpool
{
int num_threads; /*最大線程數*/
int max_queue_size; /*最大任務鏈表數*/
int do_not_block_when_full; /*當鏈表滿時是否阻塞*/
pthread_t *threads; /*線程指針*/
int cur_queue_size;
tpool_work_t *queue_head; /*鏈表頭*/
tpool_work_t *queue_tail; /*鏈表尾*/
pthread_mutex_t queue_lock; /*鏈表互斥量*/
pthread_cond_t queue_not_full; /*鏈表條件量-未滿*/
pthread_cond_t queue_not_empty; /*鏈表條件量-非空*/
pthread_cond_t queue_empty; /*鏈表條件量-空*/
int queue_closed;
int shutdown;
} tpool_t;
/* 初始化連接池 */
extern tpool_t *tpool_init(int num_worker_threads,\
int max_queue_size, int do_not_block_when_full);
/* 添加一個工作線程 */
extern int tpool_add_work(tpool_t *pool, void (*routine)(), void *arg);
/* 清除線程池*/
extern int tpool_destroy(tpool_t *pool, int finish);
#endif /* _TPOOL_H_ */