linux系統c線程池的實現

1.線程池基本原理

  在傳統服務器結構中, 常是 有一個總的 監聽線程監聽有沒有新的用戶連接服務器, 每當有一個新的 用戶進入, 服務器就開啓一個新的線程用戶處理這 個用戶的數據包。這個線程只服務於這個用戶 , 當 用戶與服務器端關閉連接以後, 服務器端銷燬這個線程。然而頻繁地開闢與銷燬線程極大地佔用了系統的資源。而且在大量用戶的情況下, 系統爲了開闢和銷燬線程將浪費大量的時間和資源。線程池提供了一個解決外部大量用戶與服務器有限資源的矛盾, 線程池和傳統的一個用戶對應一 個線程的處理方法不同, 它的基本思想就是在程序 開始時就在內存中開闢一些線程, 線程的數目是 固定的,他們獨自形成一個類, 屏蔽了對外的操作, 而服務器只需要將數據包交給線程池就可以了。當有新的客戶請求到達時 , 不是新創建一個線程爲其服務 , 而是從“池子”中選擇一個空閒的線程爲新的客戶請求服務 ,服務完畢後 , 線程進入空閒線程池中。如果沒有線程空閒 的 話, 就 將 數 據 包 暫 時 積 累 , 等 待 線 程 池 內 有 線 程空閒以後再進行處理。通過對多個任務重用已經存在的線程對象 , 降低了對線程對象創建和銷燬的開銷。當客戶請求 時 , 線程對象 已 經 存 在 , 可 以 提 高 請 求 的響應時間 , 從而整體地提高了系統服務的表現。

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

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

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

3)任務接口:每個任務必須實現的接口,當線程池的任務隊列中有可執行任務時,被空閒的工作線程調去執行(線程的閒與忙是通過互斥量實現的,跟前面文章中的設置標誌位差不多),把任務抽象出來形成接口,可以做到線程池與具體的任務無關。

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

下面的不在贅述百度《線程池技術在併發服務器中的應用》寫的非常詳細!

轉自:http://blog.csdn.net/zouxinfox/article/details/3560891

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

    下面是Linux系統下用C語言創建的一個線程池。線程池會維護一個任務鏈表(每個CThread_worker結構就是一個任務)。
    pool_init()函數預先創建好max_thread_num個線程,每個線程執thread_routine ()函數。該函數中

  1. while (pool->cur_queue_size == 0)
  2. {
  3.       pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock));
  4. }
表示如果任務鏈表中沒有任務,則該線程出於阻塞等待狀態。否則從隊列中取出任務並執行。
    
    pool_add_worker()函數向線程池的任務鏈表中加入一個任務,加入後通過調用pthread_cond_signal (&(pool->queue_ready))喚醒一個出於阻塞狀態的線程(如果有的話)。
    
    pool_destroy ()函數用於銷燬線程池,線程池任務鏈表中的任務不會再被執行,但是正在運行的線程會一直把任務運行完後再退出。
    

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/types.h>  
  5. #include <pthread.h>  
  6. #include <assert.h>  
  7.   
  8. /* 
  9. *線程池裏所有運行和等待的任務都是一個CThread_worker 
  10. *由於所有任務都在鏈表裏,所以是一個鏈表結構 
  11. */  
  12. typedef struct worker  
  13. {  
  14.     /*回調函數,任務運行時會調用此函數,注意也可聲明成其它形式*/  
  15.     void *(*process) (void *arg);  
  16.     void *arg;/*回調函數的參數*/  
  17.     struct worker *next;  
  18.   
  19. } CThread_worker;  
  20.   
  21.   
  22.   
  23. /*線程池結構*/  
  24. typedef struct  
  25. {  
  26.     pthread_mutex_t queue_lock;  
  27.     pthread_cond_t queue_ready;  
  28.   
  29.     /*鏈表結構,線程池中所有等待任務*/  
  30.     CThread_worker *queue_head;  
  31.   
  32.     /*是否銷燬線程池*/  
  33.     int shutdown;  
  34.     pthread_t *threadid;  
  35.     /*線程池中允許的活動線程數目*/  
  36.     int max_thread_num;  
  37.     /*當前等待隊列的任務數目*/  
  38.     int cur_queue_size;  
  39.   
  40. } CThread_pool;  
  41.   
  42.   
  43.   
  44. int pool_add_worker (void *(*process) (void *arg), void *arg);  
  45. void *thread_routine (void *arg);  
  46.   
  47.   
  48. //share resource  
  49. static CThread_pool *pool = NULL;  
  50. void  
  51. pool_init (int max_thread_num)  
  52. {  
  53.     pool = (CThread_pool *) malloc (sizeof (CThread_pool));  
  54.   
  55.     pthread_mutex_init (&(pool->queue_lock), NULL);  
  56.     pthread_cond_init (&(pool->queue_ready), NULL);  
  57.   
  58.     pool->queue_head = NULL;  
  59.   
  60.     pool->max_thread_num = max_thread_num;  
  61.     pool->cur_queue_size = 0;  
  62.   
  63.     pool->shutdown = 0;  
  64.   
  65.     pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof (pthread_t));  
  66.     int i = 0;  
  67.     for (i = 0; i < max_thread_num; i++)  
  68.     {   
  69.         pthread_create (&(pool->threadid[i]), NULL, thread_routine,NULL);  
  70.     }  
  71. }  
  72.   
  73.   
  74.   
  75. /*向線程池中加入任務*/  
  76. int  
  77. pool_add_worker (void *(*process) (void *arg), void *arg)  
  78. {  
  79.     /*構造一個新任務*/  
  80.     CThread_worker *newworker = (CThread_worker *) malloc (sizeof (CThread_worker));  
  81.     newworker->process = process;  
  82.     newworker->arg = arg;  
  83.     newworker->next = NULL;/*別忘置空*/  
  84.   
  85.     pthread_mutex_lock (&(pool->queue_lock));  
  86.     /*將任務加入到等待隊列中*/  
  87.     CThread_worker *member = pool->queue_head;  
  88.     if (member != NULL)  
  89.     {  
  90.         while (member->next != NULL)  
  91.             member = member->next;  
  92.         member->next = newworker;  
  93.     }  
  94.     else  
  95.     {  
  96.         pool->queue_head = newworker;  
  97.     }  
  98.   
  99.     assert (pool->queue_head != NULL);  
  100.   
  101.     pool->cur_queue_size++;  
  102.     pthread_mutex_unlock (&(pool->queue_lock));  
  103.     /*好了,等待隊列中有任務了,喚醒一個等待線程; 
  104.     注意如果所有線程都在忙碌,這句沒有任何作用*/  
  105.     pthread_cond_signal (&(pool->queue_ready));  
  106.     return 0;  
  107. }  
  108.   
  109.   
  110.   
  111. /*銷燬線程池,等待隊列中的任務不會再被執行,但是正在運行的線程會一直 
  112. 把任務運行完後再退出*/  
  113. int  
  114. pool_destroy ()  
  115. {  
  116.     if (pool->shutdown)  
  117.         return -1;/*防止兩次調用*/  
  118.     pool->shutdown = 1;  
  119.   
  120.     /*喚醒所有等待線程,線程池要銷燬了*/  
  121.     pthread_cond_broadcast (&(pool->queue_ready));  
  122.   
  123.     /*阻塞等待線程退出,否則就成殭屍了*/  
  124.     int i;  
  125.     for (i = 0; i < pool->max_thread_num; i++)  
  126.         pthread_join (pool->threadid[i], NULL);  
  127.     free (pool->threadid);  
  128.   
  129.     /*銷燬等待隊列*/  
  130.     CThread_worker *head = NULL;  
  131.     while (pool->queue_head != NULL)  
  132.     {  
  133.         head = pool->queue_head;  
  134.         pool->queue_head = pool->queue_head->next;  
  135.         free (head);  
  136.     }  
  137.     /*條件變量和互斥量也別忘了銷燬*/  
  138.     pthread_mutex_destroy(&(pool->queue_lock));  
  139.     pthread_cond_destroy(&(pool->queue_ready));  
  140.       
  141.     free (pool);  
  142.     /*銷燬後指針置空是個好習慣*/  
  143.     pool=NULL;  
  144.     return 0;  
  145. }  
  146.   
  147.   
  148.   
  149. void *  
  150. thread_routine (void *arg)  
  151. {  
  152.     printf ("starting thread 0x%x\n", pthread_self ());  
  153.     while (1)  
  154.     {  
  155.         pthread_mutex_lock (&(pool->queue_lock));  
  156.         /*如果等待隊列爲0並且不銷燬線程池,則處於阻塞狀態; 注意 
  157.         pthread_cond_wait是一個原子操作,等待前會解鎖,喚醒後會加鎖*/  
  158.         while (pool->cur_queue_size == 0 && !pool->shutdown)  
  159.         {  
  160.             printf ("thread 0x%x is waiting\n", pthread_self ());  
  161.             pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));  
  162.         }  
  163.   
  164.         /*線程池要銷燬了*/  
  165.         if (pool->shutdown)  
  166.         {  
  167.             /*遇到break,continue,return等跳轉語句,千萬不要忘記先解鎖*/  
  168.             pthread_mutex_unlock (&(pool->queue_lock));  
  169.             printf ("thread 0x%x will exit\n", pthread_self ());  
  170.             pthread_exit (NULL);  
  171.         }  
  172.   
  173.         printf ("thread 0x%x is starting to work\n", pthread_self ());  
  174.   
  175.         /*assert是調試的好幫手*/  
  176.         assert (pool->cur_queue_size != 0);  
  177.         assert (pool->queue_head != NULL);  
  178.           
  179.         /*等待隊列長度減去1,並取出鏈表中的頭元素*/  
  180.         pool->cur_queue_size--;  
  181.         CThread_worker *worker = pool->queue_head;  
  182.         pool->queue_head = worker->next;  
  183.         pthread_mutex_unlock (&(pool->queue_lock));  
  184.   
  185.         /*調用回調函數,執行任務*/  
  186.         (*(worker->process)) (worker->arg);  
  187.         free (worker);  
  188.         worker = NULL;  
  189.     }  
  190.     /*這一句應該是不可達的*/  
  191.     pthread_exit (NULL);  
  192. }  
  193.   
  194. //    下面是測試代碼  
  195.   
  196. void *  
  197. myprocess (void *arg)  
  198. {  
  199.     printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);  
  200.     sleep (1);/*休息一秒,延長任務的執行時間*/  
  201.     return NULL;  
  202. }  
  203.   
  204. int  
  205. main (int argc, char **argv)  
  206. {  
  207.     pool_init (3);/*線程池中最多三個活動線程*/  
  208.       
  209.     /*連續向池中投入10個任務*/  
  210.     int *workingnum = (int *) malloc (sizeof (int) * 10);  
  211.     int i;  
  212.     for (i = 0; i < 10; i++)  
  213.     {  
  214.         workingnum[i] = i;  
  215.         pool_add_worker (myprocess, &workingnum[i]);  
  216.     }  
  217.     /*等待所有任務完成*/  
  218.     sleep (5);  
  219.     /*銷燬線程池*/  
  220.     pool_destroy ();  
  221.   
  222.     free (workingnum);  
  223.     return 0;  
  224. }  
發佈了49 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章