線程池666666

1. 作用

線程池內部維護了多個工作線程,每個工作線程都會去任務隊列中拿取任務并執行,當執行完一個任務后不是馬上銷毀,而是繼續保留執行其它任務。顯然,線程池提高了多線程的復用率,減少了創建和銷毀線程的時間。

2. 實現原理

線程池內部由任務隊列、工作線程和管理者線程組成。

任務隊列:存儲需要處理的任務。每個任務其實就是具體的函數,在任務隊列中存儲函數指針和對應的實參。當工作線程獲取任務后,就能根據函數指針來調用指定的函數。其實現可以是數組、鏈表、STL容器等。

工作線程:有N個工作線程,每個工作線程會去任務隊列中拿取任務,然后執行具體的任務。當任務被處理后,任務隊列中就不再有該任務了。當任務隊列中沒有任務時,工作線程就會阻塞。

管理者線程:周期性檢測忙碌的工作線程數量和任務數量。當任務較多線程不夠用時,管理者線程就會多創建幾個工作線程來加快處理(不會超過工作線程數量的上限)。當任務較少線程空閑多時,管理者線程就會銷毀幾個工作線程來減少內存占用(不會低于工作線程數量的下限)。

注意:線程池中沒有維護“生產者線程”,所謂的“生產者線程”就是往任務隊列中添加任務的線程。

3. 手撕線程池

參考來源:愛編程的大丙。

【1】threadpool.c:

#include "threadpool.h"
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>#define NUMBER	2	//管理者線程增加或減少的工作線程數量//任務結構體
typedef struct Task {void (*func)(void* arg);void* arg;
} Task;//線程池結構體
struct ThreadPool {//任務隊列,視為環形隊列Task* taskQ;int queueCapacity;	//隊列容量int queueSize;		//當前任務個數int queueFront;		//隊頭 -> 取任務int queueRear;		//隊尾 -> 加任務//線程相關pthread_t managerID;	//管理者線程IDpthread_t* threadIDs;	//工作線程IDint minNum;				//工作線程最小數量int maxNum;				//工作線程最大數量int busyNum;			//工作線程忙的數量int liveNum;			//工作線程存活數量int exitNum;			//要銷毀的工作線程數量pthread_mutex_t mutexPool;	//鎖整個線程池pthread_mutex_t mutexBusy;	//鎖busyNumpthread_cond_t notFull;		//任務隊列是否滿pthread_cond_t notEmpty;	//任務隊列是否空//線程池是否銷毀int shutdown;		//釋放為1,否則為0
};/**************************************************************** 函  數: threadPoolCreate* 功  能: 創建線程池并初始化* 參  數: min---工作線程的最小數量*         max---工作線程的最大數量*		   capacity---任務隊列的最大容量* 返回值: 創建的線程池的地址**************************************************************/
ThreadPool* threadPoolCreate(int min, int max, int capacity)
{//申請線程池空間ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool));do {//此處循環只是為了便于失敗釋放空間,只會執行一次if (pool == NULL) {printf("pool create error!\n");break;}//申請任務隊列空間,并初始化pool->taskQ = (Task*)malloc(sizeof(Task) * capacity);if (pool->taskQ == NULL) {printf("Task create error!\n");break;}pool->queueCapacity = capacity;pool->queueSize = 0;pool->queueFront = 0;pool->queueRear = 0;//初始化互斥鎖和條件變量if (pthread_mutex_init(&pool->mutexPool, NULL) != 0 ||pthread_mutex_init(&pool->mutexBusy, NULL) != 0 ||pthread_cond_init(&pool->notFull, NULL) != 0 ||pthread_cond_init(&pool->notEmpty, NULL) != 0){printf("mutex or cond create error!\n");break;}//初始化shutdownpool->shutdown = 0;//初始化線程相關參數pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t) * max);if (pool->threadIDs == NULL) {printf("threadIDs create error!\n");break;}memset(pool->threadIDs, 0, sizeof(pthread_t) * max);pool->minNum = min;pool->maxNum = max;pool->busyNum = 0;pool->liveNum = min;pool->exitNum = 0;//創建管理者線程和工作線程pthread_create(&pool->managerID, NULL, manager, pool);//創建管理線程for (int i = 0; i < min; ++i) {pthread_create(&pool->threadIDs[i], NULL, worker, pool);//創建工作線程}return pool;} while (0);//申請資源失敗,釋放已分配的資源if (pool && pool->taskQ) free(pool->taskQ);if (pool && pool->threadIDs) free(pool->threadIDs);if (pool) free(pool);return NULL;
}/**************************************************************** 函  數: threadPoolDestroy* 功  能: 銷毀線程池* 參  數: pool---要銷毀的線程池* 返回值: 0表示銷毀成功,-1表示銷毀失敗**************************************************************/
int threadPoolDestroy(ThreadPool* pool)
{if (!pool) return -1;//關閉線程池pool->shutdown = 1;//阻塞回收管理者線程pthread_join(pool->managerID, NULL);//喚醒所有工作線程,讓其自殺for (int i = 0; i < pool->liveNum; ++i) {pthread_cond_signal(&pool->notEmpty);}//釋放所有互斥鎖和條件變量pthread_mutex_destroy(&pool->mutexBusy);pthread_mutex_destroy(&pool->mutexPool);pthread_cond_destroy(&pool->notEmpty);pthread_cond_destroy(&pool->notFull);//釋放堆空間if (pool->taskQ) {free(pool->taskQ);pool->taskQ = NULL;}if (pool->threadIDs) {free(pool->threadIDs);pool->threadIDs = NULL;}free(pool);pool = NULL;return 0;
}/**************************************************************** 函  數: threadPoolAdd* 功  能: 生產者往線程池的任務隊列中添加任務* 參  數: pool---線程池*		   func---函數指針,要執行的任務地址*		   arg---func指向的函數的實參* 返回值: 無**************************************************************/
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg)
{pthread_mutex_lock(&pool->mutexPool);//任務隊列滿,阻塞生產者while (pool->queueSize == pool->queueCapacity && !pool->shutdown) {pthread_cond_wait(&pool->notFull, &pool->mutexPool);}//判斷線程池是否關閉if (pool->shutdown) {pthread_mutex_unlock(&pool->mutexPool);return;}//添加任務進pool->taskQpool->taskQ[pool->queueRear].func = func;pool->taskQ[pool->queueRear].arg = arg;pool->queueSize++;pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;pthread_cond_signal(&pool->notEmpty);//喚醒工作線程pthread_mutex_unlock(&pool->mutexPool);
}/**************************************************************** 函  數: getThreadPoolBusyNum* 功  能: 獲取線程池忙的工作線程數量* 參  數: pool---線程池* 返回值: 忙的工作線程數量**************************************************************/
int getThreadPoolBusyNum(ThreadPool* pool)
{pthread_mutex_lock(&pool->mutexBusy);int busyNum = pool->busyNum;pthread_mutex_unlock(&pool->mutexBusy);return busyNum;
}/**************************************************************** 函  數: getThreadPoolAliveNum* 功  能: 獲取線程池存活的工作線程數量* 參  數: pool---線程池* 返回值: 存活的工作線程數量**************************************************************/
int getThreadPoolAliveNum(ThreadPool* pool)
{pthread_mutex_lock(&pool->mutexPool);int liveNum = pool->liveNum;pthread_mutex_unlock(&pool->mutexPool);return liveNum;
}/**************************************************************** 函  數: worker* 功  能: 工作線程的執行函數* 參  數: arg---實參傳入,這里傳入的是線程池* 返回值: 空指針**************************************************************/
void* worker(void* arg)
{ThreadPool* pool = (ThreadPool*)arg;while (1) {/* 1.取出任務隊列中的隊頭任務 */pthread_mutex_lock(&pool->mutexPool);//無任務就阻塞線程while (pool->queueSize == 0 && !pool->shutdown) {pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);//喚醒后,判斷是不是要銷毀線程if (pool->exitNum > 0) {//線程自殺pool->exitNum--;//銷毀指標-1if (pool->liveNum > pool->minNum) {pool->liveNum--;//活著的工作線程-1pthread_mutex_unlock(&pool->mutexPool);threadExit(pool);}}}//線程池關閉了就退出線程if (pool->shutdown) {pthread_mutex_unlock(&pool->mutexPool);threadExit(pool);}//取出pool中taskQ的任務Task task;task.func = pool->taskQ[pool->queueFront].func;task.arg = pool->taskQ[pool->queueFront].arg;pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;//移動隊頭pool->queueSize--;//通知生產者添加任務pthread_cond_signal(&pool->notFull);pthread_mutex_unlock(&pool->mutexPool);/* 2.設置pool的busyNum+1 */pthread_mutex_lock(&pool->mutexBusy);pool->busyNum++;pthread_mutex_unlock(&pool->mutexBusy);/* 3.執行取出的任務 */printf("thread %ld start working ...\n", pthread_self());task.func(task.arg);free(task.arg);task.arg = NULL;printf("thread %ld end working ...\n", pthread_self());/* 4.設置pool的busyNum-1 */pthread_mutex_lock(&pool->mutexBusy);pool->busyNum--;pthread_mutex_unlock(&pool->mutexBusy);}return NULL;
}/**************************************************************** 函  數: manager* 功  能: 管理者線程的執行函數* 參  數: arg---實參傳入,這里傳入的是線程池* 返回值: 空指針**************************************************************/
void* manager(void* arg)
{ThreadPool* pool = (ThreadPool*)arg;while (!pool->shutdown) {/* 每隔3秒檢測一次 */sleep(3);/* 獲取pool中相關變量 */pthread_mutex_lock(&pool->mutexPool);int taskNum = pool->queueSize;	//任務隊列中的任務數量int liveNum = pool->liveNum;	//存活的工作線程數量int busyNum = pool->busyNum;	//忙碌的工作線程數量pthread_mutex_unlock(&pool->mutexPool);/* 功能一:增加工作線程,每次增加NUMBER個 *///當任務個數大于存活工作線程數,且存活工作線程數小于最大值if (taskNum > liveNum && liveNum < pool->maxNum) {pthread_mutex_lock(&pool->mutexPool);int counter = 0;for (int i = 0; i < pool->maxNum && counter < NUMBER&& pool->liveNum < pool->maxNum; ++i){if (pool->threadIDs[i] == 0) {pthread_create(&pool->threadIDs[i], NULL, worker, pool);counter++;pool->liveNum++;}}pthread_mutex_unlock(&pool->mutexPool);}/* 功能二:銷毀工作線程,每次銷毀NUMBER個 *///當忙的線程數*2 < 存活線程數,且存活線程數 > 最小線程數if (busyNum * 2 < liveNum && liveNum > pool->minNum) {pthread_mutex_lock(&pool->mutexPool);pool->exitNum = NUMBER;//喚醒NUMBER個工作線程,讓其解除阻塞,在worker函數中自殺for (int i = 0; i < NUMBER; ++i) {pthread_cond_signal(&pool->notEmpty);}pthread_mutex_unlock(&pool->mutexPool);}}return NULL;
}/**************************************************************** 函  數: threadExit* 功  能: 工作線程退出函數,將工作線程的ID置為0,然后退出* 參  數: pool---線程池* 返回值: 無**************************************************************/
void threadExit(ThreadPool* pool)
{//將pool->threadIDs中的ID改為0pthread_t tid = pthread_self();for (int i = 0; i < pool->maxNum; i++) {if (pool->threadIDs[i] == tid) {pool->threadIDs[i] = 0;printf("threadExit() called, %ld exiting...\n", tid);break;}}pthread_exit(NULL);//退出
}

【2】threadpool.h:

#ifndef _THREADPOOL_H
#define _THREADPOOL_Htypedef struct ThreadPool ThreadPool;//創建線程池并初始化
ThreadPool* threadPoolCreate(int min, int max, int capacity);//銷毀線程池
int threadPoolDestroy(ThreadPool* pool);//給線程池添加任務
void threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg);//獲取當前忙碌的工作線程的數量
int getThreadPoolBusyNum(ThreadPool* pool);//獲取當前存活的工作線程的數量
int getThreadPoolAliveNum(ThreadPool* pool);/*********************其它函數**********************/
void* worker(void* arg);//工作線程的執行函數
void* manager(void* arg);//管理者線程的執行函數
void threadExit(ThreadPool* pool);//線程退出函數#endif

【3】main.c:

#include <stdio.h>
#include "threadpool.h"
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>//任務函數,所有線程都執行此任務
void testFunc(void* arg)
{int* num = (int*)arg;printf("thread %ld is working, number = %d\n", pthread_self(), *num);sleep(1);
}int main()
{//創建線程池: 最少3個工作線程,最多10個,任務隊列容量為100ThreadPool* pool = threadPoolCreate(3, 10, 100);//加入100個任務于任務隊列for (int i = 0; i < 100; ++i) {int* num = (int*)malloc(sizeof(int));*num = i + 100;threadPoolAdd(pool, testFunc, num);}//銷毀線程池sleep(30);//保證任務全部運行完畢threadPoolDestroy(pool);return 0;
}

【4】運行結果:

......

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

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

相關文章

git修改已提交的commit注釋

在Git中修改已經提交的commit注釋通常有以下幾種情況和相應的方法&#xff1a; 1. 修改最后一次提交的注釋&#xff08;快速修正&#xff09; 如果你想要修改的是最后一次提交的注釋&#xff0c;可以使用 --amend 選項&#xff1a; git commit --amend這個命令會將你的暫存區…

基于深度學習的光度檢測

基于深度學習的光度檢測&#xff08;Photometric Detection&#xff09;涉及從圖像中檢測和分析光照信息&#xff0c;用于多種應用&#xff0c;如場景理解、照明調節、增強現實&#xff08;AR&#xff09;、圖像增強等。以下是關于這一領域的系統介紹&#xff1a; 1. 任務和目…

JAVA基礎教程DAY1-類與方法及形參實參

首先經過C語言的學習&#xff0c;我們已經學會了基本的編程方法&#xff0c;我們知道C語言是面向過程的編程語言&#xff0c;而JAVA是面向對象的編程語言&#xff0c;所以接下來我們通過對比和舉例來進行JAVA語言的學習 首先我們來講類的概念 類&#xff1a;類是一個模板&…

Ubuntu開通5005端口 記錄

Ubuntu版本&#xff1a;20.04 使用systemctl status firewalld查看防火墻狀態&#xff0c;報錯Unit firewalld.service could not be found 報錯的原因是沒有安裝firewall&#xff0c;安裝命令為sudo apt install firewalld&#xff0c;然后進行安裝 安裝完成后輸入systemctl…

vscode jupyter選擇Python環境時找不到我安裝的Python

在一些情況下&#xff0c;我們需要自己安裝一個Python&#xff0c;在選擇內核是可能找不到指定的Python版本&#xff0c; 再次打開內核選擇頁面就能看到Python環境了 注意先到指定環境下安裝依賴包&#xff1a; ./python3 pip install ipykernel notebook jupyter

人工智能-NLP簡單知識匯總01

人工智能-NLP簡單知識匯總01 1.1自然語言處理的基本概念 自然語言處理難點&#xff1a; 語音歧義句子切分歧義詞義歧義結構歧義代指歧義省略歧義語用歧義 總而言之&#xff1a;&#xff01;&#xff01;語言無處不歧義 1.2自然語言處理的基本范式 1.2.1基于規則的方法 通…

[DataWhale大模型應用開發]學習筆記1-嘗試搭建向量數據庫

1.詞向量 1.定義 詞向量&#xff08;Word Vector&#xff09;是將單詞表示為向量形式的技術&#xff0c;是自然語言處理&#xff08;NLP&#xff09;中的一種常用方法。通過將單詞轉化為向量&#xff0c;計算機能夠更好地理解和處理語言。簡單來說&#xff0c;詞向量就是將單…

Windows系統安裝NVM,實現Node.js多版本管理

目錄 一、前言 二、NVM簡介 三、準備工作 1、卸載Node 2、創建文件夾 四、下載NVM 五、安裝NVM 六、使用NVM 1、NVM常用操作命令 2、查看NVM版本信息 3、查看Node.js版本列表&#xff1b; 4、下載指定版本Node.js 5、使用指定版本Node.js 6、查看已安裝Node.js列…

深度學習賦能數據分析,聯蔚盤云引領業務革新

一、引言 隨著大數據時代的到來&#xff0c;深度學習技術正逐漸成為企業數據分析的新引擎。聯蔚盤云憑借其在深度學習領域的深厚積累&#xff0c;為企業提供高效、精準的數據分析解決方案&#xff0c;助力企業實現業務革新與增長。 二、深度學習與數據分析的完美結合 聯蔚盤…

【區塊鏈+基礎設施】國家健康醫療大數據科創平臺 | FISCO BCOS應用案例

在醫療領域&#xff0c;疾病數據合法合規共享是亟待解決的難題。一方面&#xff0c;當一家醫院對患者實施治療后&#xff0c;若患者轉到其 他醫院就醫&#xff0c;該醫院就無法判斷診療手段是否有效。另一方面&#xff0c;醫療數據屬于個人敏感數據&#xff0c;一旦被泄露或被惡…

一個能讓渲染性能提高100倍的辦法

GPU 光線追蹤是當今的熱門話題&#xff0c;所以讓我們來談談它&#xff01;今天我們將光線追蹤一個單個球體。 使用片段著色器。 是的&#xff0c;我知道。并不特別花哨。你可以在 Shadertoy 上搜索并獲得數百個示例(https://www.shadertoy.com/results?querysphere)。甚至已…

在 Excel 中的單元格內開始一行新文本

若要在工作表單元格中開始一行新的文本或在文本的行或段之間添加間距&#xff0c;請按 AltEnter 插入換行符。 雙擊要插入換行符的單元格。 單擊所選單元格內想換行的位置。 按 AltEnter 插入換行符。

自研直播系統-直播系統實戰

文章目錄 1 流媒體基礎本文教程下載地址1.1 流媒體1.2 流式傳輸方式1.2.1 順序流式傳輸1.2.2 實時流式傳輸 1.3 流媒體傳輸協議1.3.1 rtmp協議1.3.2 HLS協議1.3.3 RTSP協議1.3.4 視頻流的對比 1.4 視頻編碼(codec)1.5 分辨率的規范分辨率簡介&#xff1a;1.5.2 分辨率單位 1.6 …

聊聊etsy平臺,一個年入百萬的項目

聊聊etsy平臺&#xff0c;一個年入百萬的項目 什么是etsy,這是怎樣一個平臺&#xff0c;怎樣盈利的&#xff1f;相信現在大家滿腦子都是這些疑問。 這個平臺也是無意間一個學員提到的&#xff0c;據說他朋友靠這個平臺年賺好幾百萬。苦于門檻太高&#xff0c;他也做不了。今天…

重磅發布|WAIC 2024最新活動日程安排完整發布!

WAIC 2024 將于 7 月在上海世博中心和世博展覽館舉行&#xff0c;論壇時間為 7 月 4 日至 6 日&#xff0c;展覽時間為 7 月 4 日至 7 日。會議涵蓋 AI 倫理治理、大模型、具身智能、投融資、教育人才等重點話題&#xff0c;體現 AI 向善等價值導向&#xff0c;9 位大獎得主和 …

Inscription Alliance的Denim協議發行首個聚合跨鏈銘文BTIA,計劃參與Mint注冊量達15萬

官方消息&#xff0c;由Inscription Alliance自主研發的創新性Denim協議發行首個聚合跨鏈銘文BTIA&#xff0c;并將于2024年7月19日公開Mint。Denim協議旨在解決當下銘文賽道流動性和互通性不足的痛點&#xff0c;基于該協議搭建的Denim Swap可以實現聚合各項協議和各條公鏈的彼…

數據結構常見圖算法

深度優先搜索 時間復雜度 領接矩陣表示 O( n2) 領接表表示 O(n+e) 空間復雜度 O(e) DFS與回溯法類似,一條路徑走到底后需要返回上一步,搜索第二條路徑。在樹的遍歷中,首先一直訪問到最深的節點,然后回溯到它的父節點,遍歷另一條路徑,直到遍歷完所有節點…

代碼隨想錄(回溯)

組合&#xff08;Leetcode77&#xff09; 思路 用遞歸每次遍歷從1-n得數&#xff0c;然后list來記錄是不是組合到k個了&#xff0c;然后這個每次for循環的開始不能和上一個值的開始重復&#xff0c;所以設置個遍歷開始索引startindex class Solution {static List<List<…

榮耀大橫評,睿藍7-450榮耀版卷出來的性價比之王

手握11萬左右預算,如何在市場內選出一輛合適自己的車?榮耀版車型無疑是當下的最佳答案。在眾多榮耀版車型中,比亞迪宋PLUS榮耀版EV520km領先型(后統稱宋PLUS榮耀版)、比亞迪元PLUS榮耀版430km領先型(后統稱元PLUS榮耀版)、比亞迪海豚PLUS榮耀版420km時尚版(后統稱海豚榮耀版)、…

中英雙語介紹美國的州:南卡羅來納州(South Carolina)

中文版 南卡羅來納州簡介 南卡羅來納州&#xff08;South Carolina&#xff09;位于美國東南部&#xff0c;是一個以其豐富的歷史、自然美景和多樣化的經濟而聞名的州。以下是對南卡羅來納州的詳細介紹&#xff0c;包括其地理位置、人口、經濟、教育、文化和主要城市等。 地…