Linux系統編程——線程池

http://blog.csdn.net/tennysonsky/article/details/46490099#

線程池基本原理

在傳統服務器結構中,常是有一個總的監聽線程監聽有沒有新的用戶連接服務器,每當有一個新的用戶進入,服務器就開啟一個新的線程用戶處理這 個用戶的數據包。這個線程只服務于這個用戶,當用戶與服務器端關閉連接以后,服務器端銷毀這個線程。(關于并發服務器更多詳情,請看《并發服務器》)。


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


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


線程池應用實例

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

1)線程管理器:用于創建并管理線程池。


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


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


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


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


線程池實現示例代碼如下:


thread_pool.h 的示例代碼:

[cpp]?view plaincopy
  1. #ifndef?__THREAD_POOL_H__??
  2. #define?__THREAD_POOL_H__??
  3. ??
  4. #include?<pthread.h>??
  5. ??
  6. ?/*********************************************************************?
  7. *?任務回調函數,也可根據需要自行修改?
  8. *********************************************************************/??
  9. typedef?void?*(*pool_task_f)(void?*arg);??
  10. ??
  11. /*********************************************************************?
  12. *?任務句柄?
  13. *********************************************************************/??
  14. typedef?struct?_task{??
  15. ????pool_task_f?process;/*回調函數,任務運行時會調用此函數,注意也可聲明成其它形式*/??
  16. ????void?*arg;?????/*回調函數的參數*/??
  17. ????struct?_task?*next;??
  18. }pool_task;??
  19. ??
  20. /*********************************************************************?
  21. *?線程池句柄?
  22. *********************************************************************/??
  23. typedef?struct??
  24. {??
  25. ????pthread_t?*threadid;????????/*?線程號?*/??
  26. ????int?threads_limit;??????????/*?線程池中允許的活動線程數目?*/??
  27. ????int?destroy_flag;???????????/*?是否銷毀線程池?,?0銷毀,1不銷毀*/??
  28. ????pool_task?*queue_head;??????/*?鏈表結構,線程池中所有等待任務?*/??
  29. ????int?task_in_queue;??????????/*?當前等待隊列的任務數目?*/??
  30. ????pthread_mutex_t?queue_lock;?/*?鎖?*/??
  31. ????pthread_cond_t?queue_ready;?/*?條件變量?*/??
  32. }pool_t;??
  33. ??
  34. /*********************************************************************?
  35. *功能:????????初始化線程池結構體并創建線程?
  36. *參數:?????????
  37. ????????????pool:線程池句柄?
  38. ????????????threads_limit:線程池中線程的數量?
  39. *返回值:???無?
  40. *********************************************************************/??
  41. void?pool_init(pool_t?*pool,?int?threads_limit);??
  42. ??
  43. /*********************************************************************?
  44. *功能:????????銷毀線程池,等待隊列中的任務不會再被執行,?
  45. ????????????但是正在運行的線程會一直,把任務運行完后再退出?
  46. *參數:????????線程池句柄?
  47. *返回值:???成功:0,失敗非0?
  48. *********************************************************************/??
  49. int?pool_uninit(pool_t?*pool);??
  50. ??
  51. /*********************************************************************?
  52. *功能:????????向線程池中添加一個任務?
  53. *參數:?????????
  54. ????????????pool:線程池句柄?
  55. ????????????process:任務處理函數?
  56. ????????????arg:任務參數?
  57. *返回值:???0?
  58. *********************************************************************/??
  59. int?pool_add_task(pool_t?*pool,?pool_task_f?process,?void?*arg);??
  60. ??
  61. ??
  62. #endif??


thread_pool.c 的示例代碼:
[cpp]?view plaincopy
  1. #include?<stdio.h>??
  2. #include?<stdlib.h>??
  3. #include?<pthread.h>??
  4. #include?<assert.h>??
  5. ??
  6. #include?"thread_pool.h"??
  7. ??
  8. static?void?*pool_thread_server(void?*arg);??
  9. ??
  10. /*********************************************************************?
  11. *功能:????????初始化線程池結構體并創建線程?
  12. *參數:?????????
  13. ????????????pool:線程池句柄?
  14. ????????????threads_limit:線程池中線程的數量?
  15. *返回值:???無?
  16. *********************************************************************/??
  17. void?pool_init(pool_t?*pool,?int?threads_limit)??
  18. {??
  19. ????pool->threads_limit?=?threads_limit;??
  20. ????pool->queue_head?=?NULL;??
  21. ????pool->task_in_queue?=?0;??
  22. ????pool->destroy_flag?=?0;??
  23. ????/*創建存放線程ID的空間*/??
  24. ????pool->threadid?=?(pthread_t?*)calloc(threads_limit,?sizeof(pthread_t));??
  25. ????int?i?=?0;??
  26. ????/*初始化互斥鎖和條件變量*/??
  27. ????pthread_mutex_init(&(pool->queue_lock),?NULL);??
  28. ????pthread_cond_init(&(pool->queue_ready),?NULL);??
  29. ????/*循環創建threads_limit個線程*/??
  30. ????for?(i?=?0;?i?<?threads_limit;?i++){??
  31. ????????pthread_create(&(pool->threadid[i]),?NULL,?pool_thread_server,?pool);??
  32. ????}??
  33. ????return;??
  34. }??
  35. ??
  36. /*********************************************************************?
  37. *功能:????????銷毀線程池,等待隊列中的任務不會再被執行,?
  38. ????????????但是正在運行的線程會一直,把任務運行完后再退出?
  39. *參數:????????線程池句柄?
  40. *返回值:???成功:0,失敗非0?
  41. *********************************************************************/??
  42. int?pool_uninit(pool_t?*pool)??
  43. {??
  44. ????pool_task?*head?=?NULL;??
  45. ????int?i;??
  46. ??????
  47. ????pthread_mutex_lock(&(pool->queue_lock));??
  48. ????if(pool->destroy_flag)/*?防止兩次調用?*/??
  49. ????????return?-1;??
  50. ????pool->destroy_flag?=?1;??
  51. ????pthread_mutex_unlock(&(pool->queue_lock));??
  52. ????/*?喚醒所有等待線程,線程池要銷毀了?*/??
  53. ????pthread_cond_broadcast(&(pool->queue_ready));??
  54. ????/*?阻塞等待線程退出,否則就成僵尸了?*/??
  55. ????for?(i?=?0;?i?<?pool->threads_limit;?i++)??
  56. ????????pthread_join(pool->threadid[i],?NULL);??
  57. ????free(pool->threadid);??
  58. ????/*?銷毀等待隊列?*/??
  59. ????pthread_mutex_lock(&(pool->queue_lock));??
  60. ????while(pool->queue_head?!=?NULL){??
  61. ????????head?=?pool->queue_head;??
  62. ????????pool->queue_head?=?pool->queue_head->next;??
  63. ????????free(head);??
  64. ????}??
  65. ????pthread_mutex_unlock(&(pool->queue_lock));??
  66. ????/*條件變量和互斥量也別忘了銷毀*/??
  67. ????pthread_mutex_destroy(&(pool->queue_lock));??
  68. ????pthread_cond_destroy(&(pool->queue_ready));??
  69. ????return?0;??
  70. }??
  71. ??
  72. /*********************************************************************?
  73. *功能:????????向任務隊列中添加一個任務?
  74. *參數:?????????
  75. ????????????pool:線程池句柄?
  76. ????????????process:任務處理函數?
  77. ????????????arg:任務參數?
  78. *返回值:???無?
  79. *********************************************************************/??
  80. static?void?enqueue_task(pool_t?*pool,?pool_task_f?process,?void?*arg)??
  81. {??
  82. ????pool_task?*task?=?NULL;??
  83. ????pool_task?*member?=?NULL;??
  84. ??????
  85. ????pthread_mutex_lock(&(pool->queue_lock));??
  86. ??????
  87. ????if(pool->task_in_queue?>=?pool->threads_limit){??
  88. ????????printf("task_in_queue?>?threads_limit!\n");??
  89. ????????pthread_mutex_unlock?(&(pool->queue_lock));??
  90. ????????return;??
  91. ????}??
  92. ??????
  93. ????task?=?(pool_task?*)calloc(1,?sizeof(pool_task));??
  94. ????assert(task?!=?NULL);??
  95. ????task->process?=?process;??
  96. ????task->arg?=?arg;??
  97. ????task->next?=?NULL;??
  98. ????pool->task_in_queue++;??
  99. ????member?=?pool->queue_head;??
  100. ????if(member?!=?NULL){??
  101. ????????while(member->next?!=?NULL)??/*?將任務加入到任務鏈連的最后位置.?*/??
  102. ????????????member?=?member->next;??
  103. ????????member->next?=?task;??
  104. ????}else{??
  105. ????????pool->queue_head?=?task;?/*?如果是第一個任務的話,就指向頭?*/??
  106. ????}??
  107. ????printf("\ttasks?%d\n",?pool->task_in_queue);??
  108. ????/*?等待隊列中有任務了,喚醒一個等待線程?*/??
  109. ????pthread_cond_signal?(&(pool->queue_ready));??
  110. ????pthread_mutex_unlock?(&(pool->queue_lock));??
  111. }??
  112. ??
  113. /*********************************************************************?
  114. *功能:????????從任務隊列中取出一個任務?
  115. *參數:????????線程池句柄?
  116. *返回值:???任務句柄?
  117. *********************************************************************/??
  118. static?pool_task?*dequeue_task(pool_t?*pool)??
  119. {??
  120. ????pool_task?*task?=?NULL;??
  121. ??????
  122. ????pthread_mutex_lock(&(pool->queue_lock));??
  123. ????/*?判斷線程池是否要銷毀了?*/??
  124. ????if(pool->destroy_flag){??
  125. ????????pthread_mutex_unlock(&(pool->queue_lock));??
  126. ????????printf("thread?0x%lx?will?be?destroyed\n",?pthread_self());??
  127. ????????pthread_exit(NULL);??
  128. ????}??
  129. ????/*?如果等待隊列為0并且不銷毀線程池,則處于阻塞狀態?*/??
  130. ????if(pool->task_in_queue?==?0){??
  131. ????????while((pool->task_in_queue?==?0)?&&?(!pool->destroy_flag)){??
  132. ????????????printf("thread?0x%lx?is?waitting\n",?pthread_self());??
  133. ????????????/*?注意:pthread_cond_wait是一個原子操作,等待前會解鎖,喚醒后會加鎖?*/??
  134. ????????????pthread_cond_wait(&(pool->queue_ready),?&(pool->queue_lock));??
  135. ????????}??
  136. ????}else{??
  137. ????????/*?等待隊列長度減去1,并取出隊列中的第一個元素?*/??
  138. ????????pool->task_in_queue--;??
  139. ????????task?=?pool->queue_head;??
  140. ????????pool->queue_head?=?task->next;??
  141. ????????printf("thread?0x%lx?received?a?task\n",?pthread_self());??
  142. ????}??
  143. ????pthread_mutex_unlock(&(pool->queue_lock));??
  144. ????return?task;??
  145. }??
  146. ??
  147. /*********************************************************************?
  148. *功能:????????向線程池中添加一個任務?
  149. *參數:?????????
  150. ????????????pool:線程池句柄?
  151. ????????????process:任務處理函數?
  152. ????????????arg:任務參數?
  153. *返回值:???0?
  154. *********************************************************************/??
  155. int?pool_add_task(pool_t?*pool,?pool_task_f?process,?void?*arg)??
  156. {??
  157. ????enqueue_task(pool,?process,?arg);??
  158. ????return?0;??
  159. }??
  160. ??
  161. /*********************************************************************?
  162. *功能:????????線程池服務程序?
  163. *參數:????????略?
  164. *返回值:???略?
  165. *********************************************************************/??
  166. static?void?*pool_thread_server(void?*arg)??
  167. {??
  168. ????pool_t?*pool?=?NULL;??
  169. ??????
  170. ????pool?=?(pool_t?*)arg;??
  171. ????while(1){??
  172. ????????pool_task?*task?=?NULL;??
  173. ????????task?=?dequeue_task(pool);??
  174. ????????/*調用回調函數,執行任務*/??
  175. ????????if(task?!=?NULL){??
  176. ????????????printf?("thread?0x%lx?is?busy\n",?pthread_self());??
  177. ????????????task->process(task->arg);??
  178. ????????????free(task);??
  179. ????????????task?=?NULL;??
  180. ????????}??
  181. ????}??
  182. ????/*這一句應該是不可達的*/??
  183. ????pthread_exit(NULL);????
  184. ????return?NULL;??
  185. }??

下面是測試代碼:

[cpp]?view plaincopy
  1. #include?<stdio.h>??
  2. #include?<unistd.h>??
  3. ??
  4. #include?"thread_pool.h"??
  5. ??
  6. void?*task_test(void?*arg)??
  7. {??
  8. ????printf("\t\tworking?on?task?%d\n",?(int)arg);??
  9. ????sleep(1);???????????/*休息一秒,延長任務的執行時間*/??
  10. ????return?NULL;??
  11. }??
  12. ??
  13. void?thread_pool_demo(void)??
  14. {??
  15. ????pool_t?pool;??
  16. ????int?i?=?0;??
  17. ??
  18. ????pool_init(&pool,?2);//初始化一個線程池,其中創建2個線程??
  19. ????sleep(1);??
  20. ????for(i?=?0;?i?<?5;?i++){??
  21. ????????sleep(1);??
  22. ????????pool_add_task(&pool,?task_test,?(void?*)i);//添加一個任務??
  23. ????}??
  24. ????sleep(4);??
  25. ??
  26. ????pool_uninit(&pool);//刪除線程池??
  27. }??
  28. ??
  29. int?main?(int?argc,?char?*argv[])??
  30. {????
  31. ????thread_pool_demo();??
  32. ????return?0;??
  33. }??

運行結果如下:




本教程示例代碼下載請點此處。


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


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383836.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383836.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383836.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Java學習筆記五】Java異常處理

異常通常分為三類&#xff1a; 程序可控制的異常&#xff1a;一般是可預見的錯誤&#xff0c;不是致命的。例如&#xff1a;除數為0&#xff0c;數組下標越界。程序不可控制的的異常&#xff1a;這種異常往往是致命的&#xff0c;但是系統可以預見的。例如&#xff1a;系統棧溢…

【C++學習筆記一】C++類和對象詳解

類定義是以關鍵字class開頭&#xff0c;后面跟類的名稱。主體是包含在一對花括號中。類定義后必須跟著一個分號或一個聲明列表。 類的對象的公共數據成員可以使用直接成員訪問運算符.來訪問。需要注意的是&#xff0c;私有的成員和受保護的成員不能直接使用成員訪問運算符來訪…

C語言實現的簡單的線程池

http://www.linuxidc.com/Linux/2013-01/77619.htm 有時我們會需要大量線程來處理一些相互獨立的任務&#xff0c;為了避免頻繁的申請釋放線程所帶來的開銷&#xff0c;我們可以使用線程池。下面是一個C語言實現的簡單的線程池。 頭文件&#xff1a; 1: #ifndef THREAD_POOL_H_…

C++獲取當前時間

可以使用windowsAPI直接獲取。 例如&#xff1a; #include<windows.h> #include<cstdio>using namespace std;int main() {SYSTEMTIME now;GetLocalTime(&now);printf("現在是%02d時%02d分%02d秒\n",now.wHour,now.wMinute,now.wSecond);printf(&…

成員函數后面加上const的作用

const表示成員函數不會修改類中的數據成員。 規則&#xff1a; 在類中被const 聲明的函數只能訪問const 函數&#xff0c;而非const 函數可以訪問任意成員函數。在成員函數中不管數據是否具有const 屬性&#xff0c;編譯器檢查的的是是否有修改&#xff08;賦值&#xff0c;自…

簡單Linux C線程池

http://www.cnblogs.com/venow/archive/2012/11/22/2779667.html 大多數的網絡服務器&#xff0c;包括Web服務器都具有一個特點&#xff0c;就是單位時間內必須處理數目巨大的連接請求&#xff0c;但是處理時間卻是比較短的。在傳統的多線程服務器模型中是這樣實現的&#xff1…

C++創建對象:棧和堆的區別

首先我們應該了解棧和堆的差別&#xff1a; 詳細信息&#xff1a;傳送門 棧相當于函數自帶的存儲空間&#xff0c;在windows下一般為2M,在Linux下一般為8M&#xff0c;存取速度稍微快一點。堆是系統的空間&#xff0c;相對較大&#xff0c;一般為2G&#xff0c;效率稍微慢一點…

IO多路復用之poll總結

http://www.cnblogs.com/Anker/p/3261006.html 1、基本知識 poll的機制與select類似&#xff0c;與select在本質上沒有多大差別&#xff0c;管理多個描述符也是進行輪詢&#xff0c;根據描述符的狀態進行處理&#xff0c;但是poll沒有最大文件描述符數量的限制。poll和select同…

【C++學習筆記二】C++繼承

繼承 繼承允許我們一句另一個類來定義一個類&#xff0c;這使得繼承和維護一個程序變得更加容易&#xff0c;也達到了重用代碼功能和提高執行效率的效果。 一般格式為&#xff1a; class 派生類名 :訪問修飾符 基類名{};其中訪問修飾符是public protected private中的一個&a…

處理大并發之二 對epoll的理解,epoll客戶端服務端代碼

http://blog.csdn.net/wzjking0929/article/details/51838370 序言&#xff1a; 該博客是一系列的博客&#xff0c;首先從最基礎的epoll說起&#xff0c;然后研究libevent源碼及使用方法&#xff0c;最后研究nginx和node.js&#xff0c;關于select,poll這里不做說明&#xff0c…

C++基類指針指向派生類(指針)

我們常用基類指針指向派生類對象來實現多態性。 私有繼承不允許基類指針指向派生類 基類指針只能訪問到基類中含有的公有成員。 當用基類指針指向派生類對象在動態分配堆上內存的時候&#xff0c;析構函數必須是虛函數! 成員如果是數據成員的話訪問的是基類的版本&#xff…

C++虛繼承中構造函數和析構函數順序問題以及原理

多重繼承的問題&#xff1a;多個類B,C,…繼承同一個類A導致如果X繼承了B,C,…那么在X中將還有多個A中成員的拷貝&#xff0c;如果想要訪問A中的成員如果不加名字空間將會導致二義性&#xff0c;這種拷貝大多是沒有實際意義的&#xff0c;為了避免這種空間浪費&#xff0c;C有虛…

一個簡單的linux線程池

http://blog.csdn.net/wzjking0929/article/details/20312675 線程池&#xff1a;簡單地說&#xff0c;線程池 就是預先創建好一批線程&#xff0c;方便、快速地處理收到的業務。比起傳統的到來一個任務&#xff0c;即時創建一個線程來處理&#xff0c;節省了線程的創建和回收的…

【C++學習筆記三】C++多態、抽象(接口)

當類之間存在多種層次結構&#xff0c;并且類之間通過繼承關聯時就會用到多態。 虛函數在子類中的覆蓋版本和該函數在基類中的原始版本必須有相同的函數簽名、函數名、形參名、常屬性。如果返回值為非類類型&#xff0c;則必須相同&#xff0c;如果是類類型A的指針或者引用&am…

C++重載和重寫的條件以及重寫后對基類函數的覆蓋

重載&#xff1a;同一個類中名字相同&#xff0c;參數列表不同的方法構成重載函數&#xff0c;和返回值沒有關系。這就意味著就算返回值不同&#xff0c;只要名字相同參數列表相同編譯器還是會報錯&#xff0c;覺得一函數被定義了兩次。 重寫&#xff1a;派生類中只要函數名字…

C++靜態成員和靜態方法

在類中&#xff0c;靜態成員可以實現多個對象之間共享數據&#xff0c;同時保證了安全性。靜態數據對該類的所有對象是公有的&#xff0c;存儲一處供所有對象使用。 注意&#xff1a; 靜態成員定義時需要在前面加上關鍵字static靜態成員必須初始化且必須在類外進行&#xff0…

基于epoll的簡單的http服務器

http://blog.csdn.net/fangjian1204/article/details/34415651 http服務器已經可以處理并發連接&#xff0c;支持多個客戶端并發訪問&#xff0c;每個連接可以持續讀寫數據&#xff0c;當然&#xff0c;這只是一個簡單的學習例子&#xff0c;還有很多bug&#xff0c;發表出來只…

C++單例模式簡單實現

有時候我們需要某個類只能被實例化一次&#xff0c;并且其他類都可以訪問到這個類&#xff0c;就需要這種設計模式。 例如我們想要做個資源管理器&#xff0c;顯然這個管理器只能有一個。 這種模式有很多實現方式&#xff0c;這里介紹最簡單的一種&#xff0c;想要了解更多可…

Linux C++ 實現線程池

http://blog.csdn.net/qq_25425023/article/details/53914609 線程池中的線程&#xff0c;在任務隊列為空的時候&#xff0c;等待任務的到來&#xff0c;任務隊列中有任務時&#xff0c;則依次獲取任務來執行&#xff0c;任務隊列需要同步。 Linux線程同步有多種方法&#xff…

C++制表符

制表符的轉義字符為\t&#xff0c;一般情況下長度為8個空格&#xff0c;這里的8個指的是從上一個字符串的開頭開始算&#xff0c;往后數8個&#xff0c;不夠的話就補空格。 如果前面的字符串的長度大于等于8個&#xff0c;例如前面字符串的長度為x,那么就會補(8-x%8)個空格 例…