Linux系統編程——線程池

來源:互聯網
上載者:User

標籤:linux   多任務編程   系統編程   線程池   

線程池基本原理

在傳統伺服器結構中,常是有一個總的監聽線程監聽有沒有新的使用者串連伺服器,每當有一個新的使用者進入,伺服器就開啟一個新的線程使用者處理這 個使用者的資料包。這個線程只服務於這個使用者,當使用者與伺服器端關閉串連以後,伺服器端銷毀這個線程。(關於並發伺服器更多詳情,請看《並發伺服器》)。


然而頻繁地開闢與銷毀線程極大地佔用了系統的資源,而且在大量使用者的情況下,系統為了開闢和銷毀線程將浪費大量的時間和資源。線程池提供了一個解決外部大量使用者與伺服器有限資源的矛盾。


線程池和傳統的一個使用者對應一個線程的處理方法不同,它的基本思想就是在程式開始時就在記憶體中開闢一些線程,線程的數目是固定的,他們獨自形成一個類,屏蔽了對外的操作,而伺服器只需要將資料包交給線程池就可以了。當有新的客戶請求到達時,不是新建立一個線程為其服務,而是從“池子”中選擇一個閒置線程為新的客戶請求服務,服務完畢後,線程進入空閑線程池中。如果沒有線程閒置話,就將資料包暫時積累, 等待線程池內有線程空閑以後再進行處理。通過對多個任務重用已經存在的線程對象,降低了對線程對象建立和銷毀的開銷。當客戶請求 時,線程對象已經存在,可以提高請求的回應時間,從而整體地提高了系統服務的表現。


線程池應用執行個體

一般來說實現一個線程池主要包括以下幾個組成部分:

1)線程管理器:用於建立並管理線程池。


2)背景工作執行緒:線程池中實際執行任務的線程。在初始化線程時會預先建立好固定數目的線程在池中,這些初始化的線程一般處於空閑狀態,一般不佔用 CPU,佔用較小的記憶體空間。


3)任務介面:每個任務必須實現的介面,當線程池的任務隊列中有可執行任務時,被閒置背景工作執行緒調去執行(線程的閑與忙是通過互斥量實現的),把任務抽象出來形成介面,可以做到線程池與具體的任務無關。


4)任務隊列:用來存放沒有處理的任務,提供一種緩衝機制,實現這種結構有好幾種方法,常用的是隊列,主要運用先進先出原理,另外一種是鏈表之類的資料結構,可以動態為它分配記憶體空間,應用中比較靈活,此教程就是用到的鏈表。


什麼時候需要建立線程池呢?簡單的說,如果一個應用需要頻繁的建立和銷毀線程,而任務執行的時間又非常短,這樣線程建立和銷毀的帶來的開銷就不容忽視,這時也是線程池該出場的機會了。如果線程建立和銷毀時間相比任務執行時間可以忽略不計,則沒有必要使用線程池了。


線程池實現範例程式碼如下:


thread_pool.h 的範例程式碼:

#ifndef __THREAD_POOL_H__#define __THREAD_POOL_H__#include <pthread.h> /********************************************************************** 任務回呼函數,也可根據需要自行修改*********************************************************************/typedef void *(*pool_task_f)(void *arg);/********************************************************************** 任務控制代碼*********************************************************************/typedef struct _task{pool_task_f process;/*回呼函數,任務運行時會調用此函數,注意也可聲明成其它形式*/void *arg;     /*回呼函數的參數*/struct _task *next;}pool_task;/********************************************************************** 線程池控制代碼*********************************************************************/typedef struct{pthread_t *threadid;/* 線程號 */int threads_limit;/* 線程池中允許的活動線程數目 */int destroy_flag;/* 是否銷毀線程池 , 0銷毀,1不銷毀*/pool_task *queue_head;    /* 鏈表結構,線程池中所有等待任務 */int task_in_queue;/* 當前等待隊列的任務數目 */pthread_mutex_t queue_lock;/* 鎖 */pthread_cond_t queue_ready;/* 條件變數 */}pool_t;/**********************************************************************功能:初始化線程池結構體並建立線程*參數:pool:線程池控制代碼threads_limit:線程池中線程的數量*傳回值:無*********************************************************************/void pool_init(pool_t *pool, int threads_limit);/**********************************************************************功能:銷毀線程池,等待隊列中的任務不會再被執行,但是正在啟動並執行線程會一直,把任務運行完後再退出*參數:線程池控制代碼*傳回值:成功:0,失敗非0*********************************************************************/int pool_uninit(pool_t *pool);/**********************************************************************功能:向線程池中添加一個任務*參數:pool:線程池控制代碼process:任務處理函數arg:任務參數*傳回值:0*********************************************************************/int pool_add_task(pool_t *pool, pool_task_f process, void *arg);#endif


thread_pool.c 的範例程式碼:
#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <assert.h>#include "thread_pool.h"static void *pool_thread_server(void *arg);/**********************************************************************功能:初始化線程池結構體並建立線程*參數:pool:線程池控制代碼threads_limit:線程池中線程的數量*傳回值:無*********************************************************************/void pool_init(pool_t *pool, int threads_limit){pool->threads_limit = threads_limit;pool->queue_head = NULL;pool->task_in_queue = 0;pool->destroy_flag = 0;/*建立存放線程ID的空間*/pool->threadid = (pthread_t *)calloc(threads_limit, sizeof(pthread_t));int i = 0;/*初始化互斥鎖和條件變數*/pthread_mutex_init(&(pool->queue_lock), NULL);pthread_cond_init(&(pool->queue_ready), NULL);/*迴圈建立threads_limit個線程*/for (i = 0; i < threads_limit; i++){pthread_create(&(pool->threadid[i]), NULL, pool_thread_server, pool);}return;}/**********************************************************************功能:銷毀線程池,等待隊列中的任務不會再被執行,但是正在啟動並執行線程會一直,把任務運行完後再退出*參數:線程池控制代碼*傳回值:成功:0,失敗非0*********************************************************************/int pool_uninit(pool_t *pool){pool_task *head = NULL;int i;pthread_mutex_lock(&(pool->queue_lock));if(pool->destroy_flag)/* 防止兩次調用 */return -1;pool->destroy_flag = 1;pthread_mutex_unlock(&(pool->queue_lock));/* 喚醒所有等待線程,線程池要銷毀了 */pthread_cond_broadcast(&(pool->queue_ready));/* 阻塞等待線程退出,否則就成殭屍了 */for (i = 0; i < pool->threads_limit; i++)pthread_join(pool->threadid[i], NULL);free(pool->threadid);/* 銷毀等待隊列 */pthread_mutex_lock(&(pool->queue_lock));while(pool->queue_head != NULL){head = pool->queue_head;pool->queue_head = pool->queue_head->next;free(head);}pthread_mutex_unlock(&(pool->queue_lock));/*條件變數和互斥量也別忘了銷毀*/pthread_mutex_destroy(&(pool->queue_lock));pthread_cond_destroy(&(pool->queue_ready));return 0;}/**********************************************************************功能:向任務隊列中添加一個任務*參數:pool:線程池控制代碼process:任務處理函數arg:任務參數*傳回值:無*********************************************************************/static void enqueue_task(pool_t *pool, pool_task_f process, void *arg){pool_task *task = NULL;pool_task *member = NULL;pthread_mutex_lock(&(pool->queue_lock));if(pool->task_in_queue >= pool->threads_limit){printf("task_in_queue > threads_limit!\n");pthread_mutex_unlock (&(pool->queue_lock));return;}task = (pool_task *)calloc(1, sizeof(pool_task));assert(task != NULL);task->process = process;task->arg = arg;task->next = NULL;pool->task_in_queue++;member = pool->queue_head;if(member != NULL){while(member->next != NULL)/* 將任務加入到任務鏈連的最後位置. */member = member->next;member->next = task;}else{pool->queue_head = task;/* 如果是第一個任務的話,就指向頭 */}printf("\ttasks %d\n", pool->task_in_queue);/* 等待隊列中有任務了,喚醒一個等待線程 */pthread_cond_signal (&(pool->queue_ready));pthread_mutex_unlock (&(pool->queue_lock));}/**********************************************************************功能:從任務隊列中取出一個任務*參數:線程池控制代碼*傳回值:任務控制代碼*********************************************************************/static pool_task *dequeue_task(pool_t *pool){pool_task *task = NULL;pthread_mutex_lock(&(pool->queue_lock));/* 判斷線程池是否要銷毀了 */if(pool->destroy_flag){pthread_mutex_unlock(&(pool->queue_lock));printf("thread 0x%lx will be destroyed\n", pthread_self());pthread_exit(NULL);}/* 如果等待隊列為0並且不銷毀線程池,則處於阻塞狀態 */if(pool->task_in_queue == 0){while((pool->task_in_queue == 0) && (!pool->destroy_flag)){printf("thread 0x%lx is waitting\n", pthread_self());/* 注意:pthread_cond_wait是一個原子操作,等待前會解鎖,喚醒後會加鎖 */pthread_cond_wait(&(pool->queue_ready), &(pool->queue_lock));}}else{/* 等待隊列長度減去1,並取出隊列中的第一個元素 */pool->task_in_queue--;task = pool->queue_head;pool->queue_head = task->next;printf("thread 0x%lx received a task\n", pthread_self());}pthread_mutex_unlock(&(pool->queue_lock));return task;}/**********************************************************************功能:向線程池中添加一個任務*參數:pool:線程池控制代碼process:任務處理函數arg:任務參數*傳回值:0*********************************************************************/int pool_add_task(pool_t *pool, pool_task_f process, void *arg){enqueue_task(pool, process, arg);return 0;}/**********************************************************************功能:線程池服務程式*參數:略*傳回值:略*********************************************************************/static void *pool_thread_server(void *arg){pool_t *pool = NULL;pool = (pool_t *)arg;while(1){pool_task *task = NULL;task = dequeue_task(pool);/*調用回呼函數,執行任務*/if(task != NULL){printf ("thread 0x%lx is busy\n", pthread_self());task->process(task->arg);free(task);task = NULL;}}/*這一句應該是不可達的*/pthread_exit(NULL); return NULL;}

下面是測試代碼:

#include <stdio.h>#include <unistd.h>#include "thread_pool.h"void *task_test(void *arg){printf("\t\tworking on task %d\n", (int)arg);sleep(1);/*休息一秒,延長任務的執行時間*/return NULL;}void thread_pool_demo(void){pool_t pool;int i = 0;pool_init(&pool, 2);//初始化一個線程池,其中建立2個線程sleep(1);for(i = 0; i < 5; i++){sleep(1);pool_add_task(&pool, task_test, (void *)i);//添加一個任務}sleep(4);pool_uninit(&pool);//刪除線程池}int main (int argc, char *argv[]){  thread_pool_demo();return 0;}

運行結果如下:




本教程範例程式碼下載請點此處。


參考資料:http://blog.csdn.net/hubi0952

Linux系統編程——線程池

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.