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

http://www.linuxidc.com/Linux/2013-01/77619.htm

有時我們會需要大量線程來處理一些相互獨立的任務,為了避免頻繁的申請釋放線程所帶來的開銷,我們可以使用線程池。下面是一個C語言實現的簡單的線程池。

頭文件:

   1: #ifndef THREAD_POOL_H__
   2: #define THREAD_POOL_H__
   3:  
   4: #include <pthread.h>
   5:  
   6: /* 要執行的任務鏈表 */
   7: typedef struct tpool_work {
   8:     void*               (*routine)(void*);       /* 任務函數 */
   9:     void                *arg;                    /* 傳入任務函數的參數 */
  10:     struct tpool_work   *next;                    
  11: }tpool_work_t;
  12:  
  13: typedef struct tpool {
  14:     int             shutdown;                    /* 線程池是否銷毀 */
  15:     int             max_thr_num;                /* 最大線程數 */
  16:     pthread_t       *thr_id;                    /* 線程ID數組 */
  17:     tpool_work_t    *queue_head;                /* 線程鏈表 */
  18:     pthread_mutex_t queue_lock;                    
  19:     pthread_cond_t  queue_ready;    
  20: }tpool_t;
  21:  
  22: /*
  23:  * @brief     創建線程池 
  24:  * @param     max_thr_num 最大線程數
  25:  * @return     0: 成功 其他: 失敗  
  26:  */
  27: int
  28: tpool_create(int max_thr_num);
  29:  
  30: /*
  31:  * @brief     銷毀線程池 
  32:  */
  33: void
  34: tpool_destroy();
  35:  
  36: /*
  37:  * @brief     向線程池中添加任務
  38:  * @param    routine 任務函數指針
  39:  * @param     arg 任務函數參數
  40:  * @return     0: 成功 其他:失敗 
  41:  */
  42: int
  43: tpool_add_work(void*(*routine)(void*), void *arg);
  44:  
  45: #endif

實現:

   1: #include <unistd.h>
   2: #include <stdlib.h>
   3: #include <errno.h>
   4: #include <string.h>
   5: #include <stdio.h>
   6:  
   7: #include "tpool.h"
   8:  
   9: static tpool_t *tpool = NULL;
  10:  
  11: /* 工作者線程函數, 從任務鏈表中取出任務并執行 */
  12: static void* 
  13: thread_routine(void *arg)
  14: {
  15:     tpool_work_t *work;
  16:     
  17:     while(1) {
  18:         /* 如果線程池沒有被銷毀且沒有任務要執行,則等待 */
  19:         pthread_mutex_lock(&tpool->queue_lock);
  20:         while(!tpool->queue_head && !tpool->shutdown) {
  21:             pthread_cond_wait(&tpool->queue_ready, &tpool->queue_lock);
  22:         }
  23:         if (tpool->shutdown) {
  24:             pthread_mutex_unlock(&tpool->queue_lock);
  25:             pthread_exit(NULL);
  26:         }
  27:         work = tpool->queue_head;
  28:         tpool->queue_head = tpool->queue_head->next;
  29:         pthread_mutex_unlock(&tpool->queue_lock);
  30:  
  31:         work->routine(work->arg);
  32:         free(work);
  33:     }
  34:     
  35:     return NULL;   
  36: }
  37:  
  38: /*
  39:  * 創建線程池 
  40:  */
  41: int
  42: tpool_create(int max_thr_num)
  43: {
  44:     int i;
  45:  
  46:     tpool = calloc(1, sizeof(tpool_t));
  47:     if (!tpool) {
  48:         printf("%s: calloc failed\n", __FUNCTION__);
  49:         exit(1);
  50:     }
  51:     
  52:     /* 初始化 */
  53:     tpool->max_thr_num = max_thr_num;
  54:     tpool->shutdown = 0;
  55:     tpool->queue_head = NULL;
  56:     if (pthread_mutex_init(&tpool->queue_lock, NULL) !=0) {
  57:         printf("%s: pthread_mutex_init failed, errno:%d, error:%s\n",
  58:             __FUNCTION__, errno, strerror(errno));
  59:         exit(1);
  60:     }
  61:     if (pthread_cond_init(&tpool->queue_ready, NULL) !=0 ) {
  62:         printf("%s: pthread_cond_init failed, errno:%d, error:%s\n", 
  63:             __FUNCTION__, errno, strerror(errno));
  64:         exit(1);
  65:     }
  66:     
  67:     /* 創建工作者線程 */
  68:     tpool->thr_id = calloc(max_thr_num, sizeof(pthread_t));
  69:     if (!tpool->thr_id) {
  70:         printf("%s: calloc failed\n", __FUNCTION__);
  71:         exit(1);
  72:     }
  73:     for (i = 0; i < max_thr_num; ++i) {
  74:         if (pthread_create(&tpool->thr_id[i], NULL, thread_routine, NULL) != 0){
  75:             printf("%s:pthread_create failed, errno:%d, error:%s\n", __FUNCTION__, 
  76:                 errno, strerror(errno));
  77:             exit(1);
  78:         }
  79:         
  80:     }    
  81:  
  82:     return 0;
  83: }
  84:  
  85: /* 銷毀線程池 */
  86: void
  87: tpool_destroy()
  88: {
  89:     int i;
  90:     tpool_work_t *member;
  91:  
  92:     if (tpool->shutdown) {
  93:         return;
  94:     }
  95:     tpool->shutdown = 1;
  96:  
  97:     /* 通知所有正在等待的線程 */
  98:     pthread_mutex_lock(&tpool->queue_lock);
  99:     pthread_cond_broadcast(&tpool->queue_ready);
 100:     pthread_mutex_unlock(&tpool->queue_lock);
 101:     for (i = 0; i < tpool->max_thr_num; ++i) {
 102:         pthread_join(tpool->thr_id[i], NULL);
 103:     }
 104:     free(tpool->thr_id);
 105:  
 106:     while(tpool->queue_head) {
 107:         member = tpool->queue_head;
 108:         tpool->queue_head = tpool->queue_head->next;
 109:         free(member);
 110:     }
 111:  
 112:     pthread_mutex_destroy(&tpool->queue_lock);    
 113:     pthread_cond_destroy(&tpool->queue_ready);
 114:  
 115:     free(tpool);    
 116: }
 117:  
 118: /* 向線程池添加任務 */
 119: int
 120: tpool_add_work(void*(*routine)(void*), void *arg)
 121: {
 122:     tpool_work_t *work, *member;
 123:     
 124:     if (!routine){
 125:         printf("%s:Invalid argument\n", __FUNCTION__);
 126:         return -1;
 127:     }
 128:     
 129:     work = malloc(sizeof(tpool_work_t));
 130:     if (!work) {
 131:         printf("%s:malloc failed\n", __FUNCTION__);
 132:         return -1;
 133:     }
 134:     work->routine = routine;
 135:     work->arg = arg;
 136:     work->next = NULL;
 137:  
 138:     pthread_mutex_lock(&tpool->queue_lock);    
 139:     member = tpool->queue_head;
 140:     if (!member) {
 141:         tpool->queue_head = work;
 142:     } else {
 143:         while(member->next) {
 144:             member = member->next;
 145:         }
 146:         member->next = work;
 147:     }
 148:     /* 通知工作者線程,有新任務添加 */
 149:     pthread_cond_signal(&tpool->queue_ready);
 150:     pthread_mutex_unlock(&tpool->queue_lock);
 151:  
 152:     return 0;    
 153: }
 154:     
 155:  

測試代碼:

   1: #include <unistd.h>
   2: #include <stdio.h>
   3: #include <stdlib.h>
   4: #include "tpool.h"
   5:  
   6: void *func(void *arg)
   7: {
   8:     printf("thread %d\n", (int)arg);
   9:     return NULL;
  10: }
  11:  
  12: int
  13: main(int arg, char **argv)
  14: {
  15:     if (tpool_create(5) != 0) {
  16:         printf("tpool_create failed\n");
  17:         exit(1);
  18:     }
  19:     
  20:     int i;
  21:     for (i = 0; i < 10; ++i) {
  22:         tpool_add_work(func, (void*)i);
  23:     }
  24:     sleep(2);
  25:     tpool_destroy();
  26:     return 0;
  27: }

這個實現是在調用tpool_destroy之后,僅將當前正在執行的任務完成之后就會退出,我們也可以修改代碼使得線程池在執行完任務鏈表中所有任務后再退出。


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

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

相關文章

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)個空格 例…

C++派生類含有成員對象構造函數析構函數順序

參考博客&#xff1a;傳送門1 當類中含有對象成員時&#xff1a; 類的構造函數要包含對成員對象的初始化&#xff0c;如果構造函數的成員初始化列表沒有包含對成員對象的初始化&#xff0c;系統會自動調用成員對象的無參構造函數。順序上&#xff1a;先調用成員對象的構造函數…

c,c++中字符串處理函數strtok,strstr,strchr,strsub

http://blog.csdn.net/wangqing_12345/article/details/51760220 1&#xff0c;字符串切割函數 函數原型&#xff1a;char *strtok(char *s, char *delim); 函數功能&#xff1a;把字符串s按照字符串delim進行分割&#xff0c;然后返回分割的結果。 函數使用說&#xff1a; 1…

C++虛基類成員可見性

詳見《CPrimer》[第五版]719頁 如果繼承路徑上沒有和虛基類成員重名的成員&#xff0c;則不存在二義性&#xff0c;因為我們僅能訪問到虛基類成員。 當訪問僅有一條繼承路徑上含有和虛基類成員重名的成員&#xff0c;也不存在二義性。派生類的成員的優先級比基類的成員高&…