首頁 系統教程 Linux Linux C下線程池的使用

Linux C下線程池的使用

Feb 13, 2024 am 11:33 AM
linux linux教程 linux系統 linux指令 shell腳本 嵌入式linux linux入門 linux學習

你是否經常遇到伺服器負載過高,無法正常存取的問題?那麼,你需要了解 Linux 系統中一個非常重要的概念—線程池。透過合理配置線程池,可以有效避免伺服器過載的問題,並提高系統的穩定性和可靠性。

執行緒池也是多執行緒的處理方式。是將“生產者”執行緒提出任務新增至“任務佇列”,然後一些執行緒自動完成“任務佇列”上的任務。

Linux C下线程池的使用

多線程編程,建立一個線程,指定去完成某一個任務,等待線程的退出。雖然能夠滿足程式需求,但是當我們需要創建大量的執行緒的時候,在創建過程以及銷毀執行緒的過程中可能會消耗大量的CPU.增加很大開銷。如:資料夾的copy、WEB伺服器的回應。

線程池就是用來解決類似於這樣的一個問題的,可以降低頻繁地創建和銷毀線程所帶來地開銷。

執行緒池技術想法:一般採用預先建立執行緒技術,也就是提前把需要用執行緒先建立一定數目。這些線程提前創建好了之後,「任務佇列」裡面假設沒有任務,那麼就讓這些線程休眠,一旦有任務,就喚醒線程去執行任務,任務執行完了,也不需要去銷毀線程,直到當你想退出或是關機時,這個時候,那麼你呼叫銷毀執行緒池地函數去銷毀執行緒。

執行緒完成任務之後不會銷毀,而是自動地執行下一個任務。而且,當任務很多,你可以有函數介面去增加執行緒數量,當任務較少時,你可以有函數介面去銷毀部分執行緒。

如果,創建和銷毀執行緒的時間比較執行任務的時間可以忽略不計,那麼我們在這種情況下面也就沒有必要用執行緒池。

「任務佇列」是一個共享資源「互斥存取」

Linux C下线程池的使用

執行緒池本質上也是一個資料結構,需要一個結構體去描述它:

struct pthread_pool //线程池的实现 
{ 
 //一般会有如下成员 
 
 //互斥锁,用来保护这个“任务队列” 
 pthread_mutex_t lock; //互斥锁  
  
 //线程条件变量 表示“任务队列”是否有任务 
 pthread_cond_t cond; //条件变量 
  
 bool shutdown; //表示是否退出程序 bool:类型 false / true 
 
 //任务队列(链表),指向第一个需要指向的任务 
 //所有的线程都从任务链表中获取任务 "共享资源" 
 struct task * task_list; 
  
 //线程池中有多个线程,每一个线程都有tid, 需要一个数组去保存tid 
 pthread_t * tids; //malloc()  
  
 //线程池中正在服役的线程数,当前线程个数 
 unsigned int active_threads; 
  
 //线程池任务队列最大的任务数量 
 unsigned int max_waiting_tasks; 
  
 //线程池任务队列上当前有多少个任务 
 unsigned int cur_waiting_tasks; 
  
 //...... 
 
}; 
 
//任务队列(链表)上面的任务结点,只要能够描述好一个任务就可以了, 
//线程会不断地任务队列取任务 
struct task  //任务结点  
{ 
 // 1. 任务结点表示的任务,“函数指针”指向任务要执行的函数(cp_file) 
 void*(* do_task)(void * arg); 
  
 //2. 指针,指向任务指向函数的参数(文件描述符) 
 void * arg; 
  
 //3. 任务结点类型的指针,指向下一个任务 
 struct task * next; 
}; 
登入後複製

執行緒池框架程式碼如下,功能自填:

操作執行緒池所需的函數介面:pthread_pool.c 、pthread_pool.h

把「執行緒池」想像成一個外包公司,你需要去完成的就是操作執行緒池所提供的函數介面。

pthread_pool.c

#include "pthread_pool.h" 
 
/* 
 init_pool: 线程池初始化函数,初始化指定的线程池中有thread_num个初始线程 
 @pool:指针,指向您要初始化的那个线程池 
 @threa_num: 您要初始化的线程池中开始的线程数量 
 返回值:  
  成功 0 
  失败 -1 
*/ 
 
int init_pool(pthread_pool * pool , unsigned int threa_num) 
{ 
 //初始化线程池的结构体 
  
 //初始化线程互斥锁 
 pthread_mutex_init(&pool->lock, NULL); 
  
 //初始化线程条件变量 
 pthread_cond_init(&pool->cond, NULL); 
 
 pool->shutdown = false ;// 不退出 
 
 pool->task_list = (struct task*)malloc(sizeof(struct task)); 
 
 pool->tids = (pthread_t *)malloc(sizeof(pthread_t) * MAX_ACTIVE_THREADS); 
 if(pool->task_list == NULL || pool->tids == NULL) 
 { 
  perror("malloc memery error"); 
  return -1; 
 } 
 
 pool->task_list->next = NULL; 
 
 //线程池中一开始初始化多少个线程来服役 
 pool->active_threads = threa_num; 
 
 //表示线程池中最多有多少个任务 
 pool->max_waiting_tasks = MAX_WAITING_TASKS; 
 
 //线程池中任务队列当前的任务数量 
 pool->cur_waiting_tasks = 0; 
 
 //创建thread_num个线程,并且让线程去执行任务调配函数, 
 //记录所有线程的tid 
 int i = 0; 
 for(i = 0; i tids)[i], NULL, routine, (void*)pool); 
  if(ret != 0) 
  { 
   perror("create thread error"); 
   return -1; 
  } 
 
  printf("[%lu]:[%s] ===> tids[%d]:[%lu]",pthread_self(), 
   __FUNCTION__, i , pool->tids[i]); 
 } 
 
 return 0; 
} 
 
/* 
 routine: 任务调配函数。 
  所有线程开始都执行此函数,此函数会不断的从线程池的任务队列 
  中取下任务结点,去执行。 
   
  任务结点中包含“函数指针” h "函数参数" 
*/ 
 
void * routine(void * arg) 
{ 
 //arg表示你的线程池的指针 
  
 while() 
 { 
  //获取线程互斥锁,lock  
   
  //当线程池没有结束的时候,不断地从线程池的任务队列取下结点 
  //去执行。 
   
  //释放线程互斥锁,unlock 
   
  //释放任务结点 
 } 
} 
 
/* 
 destroy_pool: 销毁线程池,销毁前要保证所有的任务已经完成 
*/ 
 
int destroy_pool(pthread_pool * pool) 
{ 
 //释放所有空间 等待任务执行完毕(join)。 
 //唤醒所有线程 
 //利用join函数回收每一个线程资源。 
} 
 
/* 
 add_task:给任务队列增加任务, 把do_task指向的任务(函数指针)和 
  arg指向的参数保存到一个任务结点,添加到pool任务队列中。 
   
 @pool : 您要添加任务的线程池 
 @do_task : 您需要添加的任务(cp_file) 
 @arg: 您要执行的任务的参数(文件描述符) 
*/ 
 
int add_task(pthread_pool *pool,void*(* do_task)(void * arg), void*arg) 
{ 
 //把第二个参数和第三个参数封装成struct task  
  
 //再把它添加到 pool->task 任务队列中去 
  
 //注意任务队列是一个共享资源 
  
 //假如任务后要唤醒等待的线程。 
} 
 
//如果任务多的时候,往线程池中添加线程  pthread_create 
int add_threads(pthread_pool * pool, unsigned int num); 
{ 
 //新创建num个线程,让每一个线程去执行线程调配函数 
  
 //将每一个新创建的线程tid,添加到pool-> tids  
} 
 
//如果任务少的时候,减少线程池中线程的数量 pthread_cancel join 
int remove_threads(pthread_pool * pool, unsigned int num) 
{ 
 //用pthread_cancel取消num个线程  
 //利用pthread_join函数去回收资源。 
} 
登入後複製

pthread_pool.h

#ifndef __PTHREAD_POOL_H__ 
#define __PTHREAD_POOL_H__ 
 
//表示线程池中最多有多少个线程 
#define MAX_ACTIVE_THREADS 20 
 
//表示线程池中最多有多少个任务 
#define MAX_WAITING_TASKS 1024 
 
//任务队列(链表)上面的任务结点,只要能够描述好一个任务就可以了, 
//线程会不断地任务队列取任务 
struct task  //任务结点  
{ 
 // 1. 任务结点表示的任务,“函数指针”指向任务要执行的函数(cp_file) 
 void*(* do_task)(void * arg); 
  
 //2. 指针,指向任务指向函数的参数(文件描述符) 
 void * arg; 
  
 //3. 任务结点类型的指针,指向下一个任务 
 struct task * next; 
}; 
 
struct pthread_pool //线程池的实现 
{ 
 //一般会有如下成员 
 
 //互斥锁,用来保护这个“任务队列” 
 pthread_mutex_t lock; //互斥锁  
  
 //线程条件变量 表示“任务队列”是否有任务 
 pthread_cond_t cond; //条件变量 
  
 bool shutdown; //表示是否退出程序 bool:类型 false / true 
 
 //任务队列(链表),指向第一个需要指向的任务 
 //所有的线程都从任务链表中获取任务 "共享资源" 
 struct task * task_list; 
  
 //线程池中有多个线程,每一个线程都有tid, 需要一个数组去保存tid 
 pthread_t * tids; //malloc()  
  
 //线程池中正在服役的线程数,当前线程个数 
 unsigned int active_threads; 
  
 //线程池任务队列最大的任务数量 
 unsigned int max_waiting_tasks; 
  
 //线程池任务队列上当前有多少个任务 
 unsigned int cur_waiting_tasks; 
  
 //...... 
 
}; 
 
/* 
 init_pool: 线程池初始化函数,初始化指定的线程池中有thread_num 
  个初始线程 
 @pool:指针,指向您要初始化的那个线程池 
 @threa_num: 您要初始化的线程池中开始的线程数量 
 返回值:  
  成功 0 
  失败 -1 
*/ 
 
int init_pool(pthread_pool * pool , unsigned int threa_num); 
 
/* 
 routine: 任务调配函数。 
  所有线程开始都执行此函数,此函数会不断的从线程池的任务队列 
  中取下任务结点,去执行。 
   
  任务结点中包含“函数指针” h "函数参数" 
*/ 
 
void * routine(void * arg); 
 
/* 
 destroy_pool: 销毁线程池,销毁前要保证所有的任务已经完成 
*/ 
 
int destroy_pool(pthread_pool * pool); 
 
/* 
 add_task:给任务队列增加任务, 把do_task指向的任务(函数指针)和 
  arg指向的参数保存到一个任务结点,添加到pool任务队列中。 
   
 @pool : 您要添加任务的线程池 
 @do_task : 您需要添加的任务(cp_file) 
 @arg: 您要执行的任务的参数(文件描述符) 
*/ 
 
int add_task(pthread_pool *pool,void*(* do_task)(void * arg), void*arg); 
 
//如果任务多的时候,往线程池中添加线程  pthread_create 
int add_threads(pthread_pool * pool, unsigned int num); 
 
 
//如果任务少的时候,减少线程池中线程的数量 pthread_cancel join 
int remove_threads(pthread_pool * pool, unsigned int num); 
 
#endif 
登入後複製

以上是Linux C下線程池的使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

centos和ubuntu的區別 centos和ubuntu的區別 Apr 14, 2025 pm 09:09 PM

CentOS 和 Ubuntu 的關鍵差異在於:起源(CentOS 源自 Red Hat,面向企業;Ubuntu 源自 Debian,面向個人)、包管理(CentOS 使用 yum,注重穩定;Ubuntu 使用 apt,更新頻率高)、支持週期(CentOS 提供 10 年支持,Ubuntu 提供 5 年 LTS 支持)、社區支持(CentOS 側重穩定,Ubuntu 提供廣泛教程和文檔)、用途(CentOS 偏向服務器,Ubuntu 適用於服務器和桌面),其他差異包括安裝精簡度(CentOS 精

centos如何安裝 centos如何安裝 Apr 14, 2025 pm 09:03 PM

CentOS 安裝步驟:下載 ISO 映像並刻錄可引導媒體;啟動並選擇安裝源;選擇語言和鍵盤佈局;配置網絡;分區硬盤;設置系統時鐘;創建 root 用戶;選擇軟件包;開始安裝;安裝完成後重啟並從硬盤啟動。

Centos停止維護後的選擇 Centos停止維護後的選擇 Apr 14, 2025 pm 08:51 PM

CentOS 已停止維護,替代選擇包括:1. Rocky Linux(兼容性最佳);2. AlmaLinux(與 CentOS 兼容);3. Ubuntu Server(需要配置);4. Red Hat Enterprise Linux(商業版,付費許可);5. Oracle Linux(與 CentOS 和 RHEL 兼容)。在遷移時,考慮因素有:兼容性、可用性、支持、成本和社區支持。

docker desktop怎麼用 docker desktop怎麼用 Apr 15, 2025 am 11:45 AM

如何使用 Docker Desktop? Docker Desktop 是一款工具,用於在本地機器上運行 Docker 容器。其使用步驟包括:1. 安裝 Docker Desktop;2. 啟動 Docker Desktop;3. 創建 Docker 鏡像(使用 Dockerfile);4. 構建 Docker 鏡像(使用 docker build);5. 運行 Docker 容器(使用 docker run)。

docker原理詳解 docker原理詳解 Apr 14, 2025 pm 11:57 PM

Docker利用Linux內核特性,提供高效、隔離的應用運行環境。其工作原理如下:1. 鏡像作為只讀模板,包含運行應用所需的一切;2. 聯合文件系統(UnionFS)層疊多個文件系統,只存儲差異部分,節省空間並加快速度;3. 守護進程管理鏡像和容器,客戶端用於交互;4. Namespaces和cgroups實現容器隔離和資源限制;5. 多種網絡模式支持容器互聯。理解這些核心概念,才能更好地利用Docker。

centos停止維護後怎麼辦 centos停止維護後怎麼辦 Apr 14, 2025 pm 08:48 PM

CentOS 停止維護後,用戶可以採取以下措施應對:選擇兼容髮行版:如 AlmaLinux、Rocky Linux、CentOS Stream。遷移到商業發行版:如 Red Hat Enterprise Linux、Oracle Linux。升級到 CentOS 9 Stream:滾動發行版,提供最新技術。選擇其他 Linux 發行版:如 Ubuntu、Debian。評估容器、虛擬機或云平台等其他選項。

docker鏡像失敗怎麼辦 docker鏡像失敗怎麼辦 Apr 15, 2025 am 11:21 AM

Docker鏡像構建失敗的故障排除步驟:檢查Dockerfile語法和依賴項版本。檢查構建上下文中是否包含所需源代碼和依賴項。查看構建日誌以獲取錯誤詳細信息。使用--target選項構建分層階段以識別失敗點。確保使用最新版本的Docker引擎。使用--t [image-name]:debug模式構建鏡像以調試問題。檢查磁盤空間並確保足夠。禁用SELinux以防止干擾構建過程。向社區平台尋求幫助,提供Dockerfile和構建日誌描述以獲得更具體的建議。

怎麼看docker進程 怎麼看docker進程 Apr 15, 2025 am 11:48 AM

Docker 進程查看方法:1. Docker CLI 命令:docker ps;2. Systemd CLI 命令:systemctl status docker;3. Docker Compose CLI 命令:docker-compose ps;4. Process Explorer(Windows);5. /proc 目錄(Linux)。

See all articles