消息分類 ==> 線程創建 ==> 傳遞消息到子線程 ==> 線程分離 ==> 在子線程中執行任務 ==> 任務結束退出; 對大多數小型局域網的通信來說,上述方法足夠滿足需求;但當我們的通信范圍擴大到廣域網或大型局域網通信中時,我們將面臨大量消息頻繁請求服務器;在這種情況下,創" />

在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何用C語言實現線程池

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-13 10:41 ? 次閱讀

線程池是一種多線程處理形式,大多用于高并發服務器上,它能合理有效的利用高并發服務器上的線程資源;線程與進程用于處理各項分支子功能,我們通常的操作是:接收消息 ==> 消息分類 ==> 線程創建 ==> 傳遞消息到子線程 ==> 線程分離 ==> 在子線程中執行任務 ==> 任務結束退出;

對大多數小型局域網的通信來說,上述方法足夠滿足需求;但當我們的通信范圍擴大到廣域網或大型局域網通信中時,我們將面臨大量消息頻繁請求服務器;在這種情況下,創建與銷毀線程都已經成為一種奢侈的開銷,特別對于嵌入式服務器來說更應保證內存資源的合理利用;

因此,線程池技術應運而生;線程池允許一個線程可以多次復用,且每次復用的線程內部的消息處理可以不相同,將創建與銷毀的開銷省去而不必來一個請求開一個線程;

結構講解:

線程池是一個抽象的概念,其內部由任務隊列,一堆線程,管理者線程組成;

圖片

我們將以上圖為例,實現一個最基礎的線程池,接下來將分部分依次講解;講解順序為:1.線程池總體結構 2.線程數組 3.任務隊列 4.管理者線程 5.使用線程池接口的例子

一、線程池總體結構

這里講解線程池在邏輯上的結構體;看下方代碼,該結構體threadpool_t中包含線程池狀態信息,任務隊列信息以及多線程操作中的互斥鎖;在任務結構體中包含了一個可以放置多種不同任務函數的函數指針,一個傳入該任務函數的void*類型的參數

注意:在使用時需要將你的消息分類處理函數裝入任務的(*function);然后放置到任務隊列并通知空閑線程;

線程池狀態信息:描述當前線程池的基本信息,如是否開啟、最小線程數、最大線程數、存活線程數、忙線程數、待銷毀線程數等… …

任務隊列信息:描述當前任務隊列基本信息,如最大任務數、隊列不為滿條件變量、隊列不為空條件變量等… …

多線程互斥鎖:保證在同一時間點上只有一個線程在任務隊列中取任務并修改任務隊列信息、修改線程池信息;

函數指針:在打包消息階段,將分類后的消息處理函數放在(*function);

void*類型參數:用于傳遞消息處理函數需要的信息;

/ 任務 /

typedef struct {

void *(*function)(void *);

void *arg;

} threadpool_task_t;

/ 線程池管理 /

struct threadpool_t{

pthread_mutex_t lock; /* 鎖住整個結構體 */

pthread_mutex_t thread_counter; /* 用于使用忙線程數時的鎖 */

pthread_cond_t queue_not_full; /* 條件變量,任務隊列不為滿 */

pthread_cond_t queue_not_empty; /* 任務隊列不為空 */

pthread_t threads; / 存放線程的tid,實際上就是管理了線 數組 */

pthread_t admin_tid; /* 管理者線程tid */

threadpool_task_t task_queue; / 任務隊列 */

/ 線程池信息 /

int min_thr_num; /* 線程池中最小線程數 */

int max_thr_num; /* 線程池中最大線程數 */

int live_thr_num; /* 線程池中存活的線程數 */

int busy_thr_num; /* 忙線程,正在工作的線程 */

int wait_exit_thr_num; /* 需要銷毀的線程數 */

/ 任務隊列信息 /

int queue_front; /* 隊頭 */

int queue_rear; /* 隊尾 */

int queue_size;

/* 存在的任務數 */

int queue_max_size; /* 隊列能容納的最大任務數 */

/ 線程池狀態 /

int shutdown; /* true為關閉 */

};

/ 創建線程池 /

threadpool_t *

threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size)

{ /* 最小線程數 最大線程數 最大任務數*/

int i;

threadpool_t *pool = NULL;

do

{

/* 線程池空間開辟 */

if ((pool=(threadpool_t *)malloc(sizeof(threadpool_t))) == NULL)

{

printf("malloc threadpool false; n");

break;

}

/ 信息初始化 /

pool->min_thr_num = min_thr_num;

pool->max_thr_num = max_thr_num;

pool->busy_thr_num = 0;

pool->live_thr_num = min_thr_num;

pool->wait_exit_thr_num = 0;

pool->queue_front = 0;

pool->queue_rear = 0;

pool->queue_size = 0;

pool->queue_max_size = queue_max_size;

pool->shutdown = false;

/* 根據最大線程數,給工作線程數組開空間,清0 */

pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);

if (pool->threads == NULL)

{

printf("malloc threads false;n");

break;

}

memset(pool->threads, 0, sizeof(pthread_t)*max_thr_num);

/* 隊列開空間 */

pool->task_queue =

(threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);

if (pool->task_queue == NULL)

{

printf("malloc task queue false;n");

break;

}

/* 初始化互斥鎖和條件變量 */

if ( pthread_mutex_init(&(pool->lock), NULL) != 0 ||

pthread_mutex_init(&(pool->thread_counter), NULL) !=0 ||

pthread_cond_init(&(pool->queue_not_empty), NULL) !=0 ||

pthread_cond_init(&(pool->queue_not_full), NULL) !=0)

{

printf("init lock or cond false;n");

break;

}

/* 啟動min_thr_num個工作線程 */

for (i=0; i

{

/* pool指向當前線程池 threadpool_thread函數在后面講解 */

pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);

printf("start thread 0x%x... n", (unsigned int)pool->threads[i]);

}

/* 管理者線程 admin_thread函數在后面講解 */

pthread_create(&(pool->admin_tid), NULL, admin_thread, (void *)pool);

return pool;

} while(0);

/* 釋放pool的空間 */

threadpool_free(pool);

return NULL;

}

二、線程數組

線程數組實際上是在線程池初始化時開辟的一段存放一堆線程tid的空間,在邏輯上形成一個池,里面放置著提前創建的線程;這段空間中包含了正在工作的線程,等待工作的線程(空閑線程),等待被銷毀的線程,申明但沒有初始化的線程空間;

圖片

/ 工作線程 /

void *

threadpool_thread(void *threadpool)

{

threadpool_t *pool = (threadpool_t *)threadpool;

threadpool_task_t task;

while (true)

{

pthread_mutex_lock(&(pool->lock));

/* 無任務則阻塞在 “任務隊列不為空” 上,有任務則跳出 */

while ((pool->queue_size == 0) && (!pool->shutdown))

{

printf("thread 0x%x is waiting n", (unsigned int)pthread_self());

pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock));

/* 判斷是否需要清除線程,自殺功能 */

if (pool->wait_exit_thr_num > 0)

{

pool->wait_exit_thr_num--;

/* 判斷線程池中的線程數是否大于最小線程數,是則結束當前線程 */

if (pool->live_thr_num > pool->min_thr_num)

{

printf("thread 0x%x is exiting n", (unsigned int)pthread_self());

pool->live_thr_num--;

pthread_mutex_unlock(&(pool->lock));

pthread_exit(NULL);//結束線程

}

}

}

/* 線程池開關狀態 */

if (pool->shutdown) //關閉線程池

{

pthread_mutex_unlock(&(pool->lock));

printf("thread 0x%x is exiting n", (unsigned int)pthread_self());

pthread_exit(NULL); //線程自己結束自己

}

//否則該線程可以拿出任務

task.function = pool->task_queue[pool->queue_front].function; //出隊操作

task.arg = pool->task_queue[pool->queue_front].arg;

pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size; //環型結構

pool->queue_size--;

//通知可以添加新任務

pthread_cond_broadcast(&(pool->queue_not_full));

//釋放線程鎖

pthread_mutex_unlock(&(pool->lock));

//執行剛才取出的任務

printf("thread 0x%x start working n", (unsigned int)pthread_self());

pthread_mutex_lock(&(pool->thread_counter)); //鎖住忙線程變量

pool->busy_thr_num++;

pthread_mutex_unlock(&(pool->thread_counter));

(*(task.function))(task.arg); //執行任務

//任務結束處理

printf("thread 0x%x end working n", (unsigned int)pthread_self());

pthread_mutex_lock(&(pool->thread_counter));

pool->busy_thr_num--;

pthread_mutex_unlock(&(pool->thread_counter));

}

pthread_exit(NULL);

}

三、任務隊列

任務隊列的存在形式與線程數組相似;在線程池初始化時根據傳入的最大任務數開辟空間;當服務器前方后請求到來后,分類并打包消息成為任務,將任務放入任務隊列并通知空閑線程來取;不同之處在于任務隊列有明顯的先后順序,先進先出;而線程數組中的線程則是一個競爭關系去拿到互斥鎖爭取任務;

圖片

/ 向線程池的任務隊列中添加一個任務 /

int

threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg)

{

pthread_mutex_lock(&(pool->lock));

/ 如果隊列滿了,調用wait阻塞 /

while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown))

pthread_cond_wait(&(pool->queue_not_full), &(pool->lock));

/ 如果線程池處于關閉狀態 /

if (pool->shutdown)

{

pthread_mutex_unlock(&(pool->lock));

return -1;

}

/ 清空工作線程的回調函數的參數arg /

if (pool->task_queue[pool->queue_rear].arg != NULL)

{

free(pool->task_queue[pool->queue_rear].arg);

pool->task_queue[pool->queue_rear].arg = NULL;

}

/ 添加任務到任務隊列 /

pool->task_queue[pool->queue_rear].function = function;

pool->task_queue[pool->queue_rear].arg = arg;

pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size; /* 邏輯環 */

pool->queue_size++;

/ 添加完任務后,隊列就不為空了,喚醒線程池中的一個線程 /

pthread_cond_signal(&(pool->queue_not_empty));

pthread_mutex_unlock(&(pool->lock));

return 0;

}

四、管理者線程

作為線程池的管理者,該線程的主要功能包括:檢查線程池內線程的存活狀態,工作狀態;負責根據服務器當前的請求狀態去動態的增加或刪除線程,保證線程池中的線程數量維持在一個合理高效的平衡上;

說到底,它就是一個單獨的線程,定時的去檢查,根據我們的一個維持平衡算法去增刪線程;

/ 管理線程 /

void *

admin_thread(void *threadpool)

{

int i;

threadpool_t *pool = (threadpool_t *)threadpool;

while (!pool->shutdown)

{

printf("admin -----------------n");

sleep(DEFAULT_TIME); / 隔一段時間再管理 /

pthread_mutex_lock(&(pool->lock)); / 加鎖 /

int queue_size = pool->queue_size; / 任務數 /

int live_thr_num = pool->live_thr_num; / 存活的線程數 /

pthread_mutex_unlock(&(pool->lock)); / 解鎖 /

pthread_mutex_lock(&(pool->thread_counter));

int busy_thr_num = pool->busy_thr_num; / 忙線程數 /

pthread_mutex_unlock(&(pool->thread_counter));

printf("admin busy live -%d--%d-n", busy_thr_num, live_thr_num);

/ 創建新線程 實際任務數量大于 最小正在等待的任務數量,存活線程數小于最大線程數 /

if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num <= pool->max_thr_num)

{

printf("admin add-----------n");

pthread_mutex_lock(&(pool->lock));

int add=0;

/ 一次增加 DEFAULT_THREAD_NUM 個線程 /

for (i=0; imax_thr_num && add

&& pool->live_thr_num < pool->max_thr_num; i++)

{

if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i]))

{

pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);

add++;

pool->live_thr_num++;

printf("new thread -----------------------n");

}

}

pthread_mutex_unlock(&(pool->lock));

}

/ 銷毀多余的線程 忙線程x2 都小于 存活線程,并且存活的大于最小線程數 /

if ((busy_thr_num*2) < live_thr_num && live_thr_num > pool->min_thr_num)

{

// printf("admin busy --%d--%d----n", busy_thr_num, live_thr_num);

/ 一次銷毀DEFAULT_THREAD_NUM個線程 /

pthread_mutex_lock(&(pool->lock));

pool->wait_exit_thr_num = DEFAULT_THREAD_NUM;

pthread_mutex_unlock(&(pool->lock));

for (i=0; i

{

//通知正在處于空閑的線程,自殺

pthread_cond_signal(&(pool->queue_not_empty));

printf("admin cler --n");

}

}

}

return NULL;

/ 線程是否存活 /

int

is_thread_alive(pthread_t tid)

{

int kill_rc = pthread_kill(tid, 0); //發送0號信號,測試是否存活

if (kill_rc == ESRCH) //線程不存在

{

return false;

}

return true;

}

五、釋放

/ 釋放線程池 /

int

threadpool_free(threadpool_t *pool)

{

if (pool == NULL)

return -1;

if (pool->task_queue)

free(pool->task_queue);

if (pool->threads)

{

free(pool->threads);

pthread_mutex_lock(&(pool->lock)); / 先鎖住再銷毀 /

pthread_mutex_destroy(&(pool->lock));

pthread_mutex_lock(&(pool->thread_counter));

pthread_mutex_destroy(&(pool->thread_counter));

pthread_cond_destroy(&(pool->queue_not_empty));

pthread_cond_destroy(&(pool->queue_not_full));

}

free(pool);

pool = NULL;

return 0;

}

/ 銷毀線程池 /

int

threadpool_destroy(threadpool_t *pool)

{

int i;

if (pool == NULL)

{

return -1;

}

pool->shutdown = true;

/ 銷毀管理者線程 /

pthread_join(pool->admin_tid, NULL);

//通知所有線程去自殺(在自己領任務的過程中)

for (i=0; ilive_thr_num; i++)

{

pthread_cond_broadcast(&(pool->queue_not_empty));

}

/ 等待線程結束 先是pthread_exit 然后等待其結束 /

for (i=0; ilive_thr_num; i++)

{

pthread_join(pool->threads[i], NULL);

}

threadpool_free(pool);

return 0;

}

六、接口

/* 線程池初始化,其管理者線程及工作線程都會啟動 */

threadpool_t *thp = threadpool_create(10, 100, 100);

printf("threadpool init ... ... n");

/* 接收到任務后添加 */

threadpool_add_task(thp, do_work, (void *)p);

// ... ...

/* 銷毀 */

threadpool_destroy(thp);

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8600

    瀏覽量

    151166
  • 服務器
    +關注

    關注

    12

    文章

    9160

    瀏覽量

    85428
  • C語言
    +關注

    關注

    180

    文章

    7604

    瀏覽量

    136841
  • 廣域網
    +關注

    關注

    1

    文章

    246

    瀏覽量

    21806
  • 線程池
    +關注

    關注

    0

    文章

    57

    瀏覽量

    6847
收藏 人收藏

    評論

    相關推薦

    C語言線程實現方案

    這是一個簡單小巧的C語言線程實現,在 Github 上有 1.1K 的 star,很適合用來學習 Linux 的多
    的頭像 發表于 01-29 16:43 ?1540次閱讀

    求助:如何用C語言實現直接尋址

    何用C語言實現直接尋址,就像匯編里面的mov 0x80,0x60
    發表于 05-13 16:39

    何用C語言實現OOP編程?

    老大看到OOP編程很好,就讓我學,怎么用C語言實現OOP編程的,請大俠指點
    發表于 10-30 03:45

    何用C語言實現一款猜數字游戲

    何用C語言實現一款猜數字游戲
    發表于 01-06 07:10

    何用VHDL語言實現幀同步的設計?

    幀同步是什么工作原理?如何用VHDL語言實現幀同步的設計?
    發表于 04-08 06:33

    何用C語言實現面向對象編程

    、組合、多態等面向對象的功能,但C語言有struct和函數指針。我們可以用struct中的數據和函數指針,以此來模擬對象和類的行為。所以在正式開始設計模式前,先看看如何用C
    發表于 07-12 07:24

    何用C語言實現顯示16只燈的狀態并開關燈?

    何用C語言實現顯示16只燈的狀態并開關燈?
    發表于 10-19 09:39

    何用C語言實現字符數組轉換為16進制數組?

    何用C語言實現字符數組轉換為16進制數組?
    發表于 11-03 07:47

    線程是如何實現

    線程的概念是什么?線程是如何實現的?
    發表于 02-28 06:20

    DSP算法的c語言實現

    DSP算法的c語言實現,又需要的朋友下來看看。
    發表于 05-09 10:59 ?0次下載

    累加校驗和C語言實現

    累加校驗和C語言實現
    發表于 11-29 18:06 ?10次下載
    累加校驗和<b class='flag-5'>C</b><b class='flag-5'>語言實現</b>

    怎么用C語言實現多態

    這里我想主要介紹下在C語言中是如何實現的面向對象。知道了C語言實現面向對象的方式,我們再聯想下,C
    的頭像 發表于 10-12 09:12 ?2058次閱讀

    何用C++實現一個線程呢?

    C++線程是一種多線程管理模型,把線程分成任務執行和線程調度兩部分。
    發表于 06-08 14:53 ?1779次閱讀
    如<b class='flag-5'>何用</b><b class='flag-5'>C</b>++<b class='flag-5'>實現</b>一個<b class='flag-5'>線程</b><b class='flag-5'>池</b>呢?

    線程基本概念與原理

    一、線程基本概念與原理 1.1 線程概念及優勢 C++線程
    的頭像 發表于 11-10 10:24 ?537次閱讀

    什么是動態線程?動態線程的簡單實現思路

    因此,動態可監控線程一種針對以上痛點開發的線程管理工具。主要可實現功能有:提供對 Spring 應用內
    的頭像 發表于 02-28 10:42 ?645次閱讀
    主站蜘蛛池模板: 97伊人| 午夜精品在线| 手机看片国产免费永久| 欧美爆操| 亚洲97在线| 国内精品久久久久影院薰衣草| 天堂资源在线8| 亚洲国产日韩女人aaaaaa毛片在线| 四只虎免费永久观看| 成人a在线| 欧美黄免在线播放| 色综合久久丁香婷婷| bt天堂网在线资源www| 男人操女人的网站| 色碰人色碰人视频| 亚洲午夜免费| 亚洲色图27p| 男人和女人做a免费视频| 日本噜噜影院| 一区二区三区欧美在线| 国产美女视频一区二区三区| www天天操| 四虎永久在线观看视频精品| 777人体粉嫩u美图| 91大神网址| 欧美福利片在线观看| 欧美色老太婆| 亚洲欧美日本综合| 成人xxxxx| 亚洲色图图片专区| 久久国产精品99久久久久久老狼| 久草资源网| 四虎影视在线影院4hutv| 亚洲精品久久片久久| 欧美三四级片| 国产日韩精品一区二区三区| 人人揉揉香蕉大青草| 欧美色图 亚洲| 国产欧美日韩va| 色噜噜狠狠狠狠色综合久一| 天天欧美|