Linux:线程池

ops/2024/11/1 22:31:01/

什么是线程池

线程池就是一个容纳多个线程的容器,对于一线线程我们可以多次对此线程进行重复使用,从而省去频繁创建线程对象的操作。

妈的写死我了。。回来再说,金工实习去了

#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> 
//来写一个线程池,线程池需要一个存储任务的队列,线程池的容器,线程执行的任务
//任务队列创造
typedef struct task{void* arg;//指向指向函数的参数void(*run_task)(void*arg);//指向任务函数的指针struct task *next;  //next指针,指向下一个任务节点
}task;
//创建线程池
typedef struct thread_pool{task* first;//队列的开头task* end;//队列结尾int threadNum;//线程池数量int tasksize;//任务队列的大小pthread_mutex_t mutex_pool;//线程池的锁pthread_cond_t notempty;//确认队列是不是空pthread_t*threads;int shutdowm;//是否销毁线程池
}pthread_pool;
//创建接口//执行任务
void* thread_work(void*arg){pthread_pool*pool=(pthread_pool*)arg;while (1) {pthread_mutex_lock(&pool->mutex_pool);// 如果没有任务且线程池未关闭,等待任务while (pool->tasksize == 0 && !pool->shutdowm) {pthread_cond_wait(&pool->notempty, &pool->mutex_pool);}// 如果线程池关闭且任务为空,退出线程if (pool->shutdowm && pool->tasksize == 0) {pthread_mutex_unlock(&pool->mutex_pool);pthread_exit(NULL);}// 获取任务task* t = pool->first;pool->first = t->next;if (pool->first == NULL) {pool->end = NULL;}pool->tasksize--;pthread_mutex_unlock(&pool->mutex_pool);// 执行任务t->run_task(t->arg);free(t);}
}
//给线程池添加任务
void addWork(pthread_pool* pool, void* arg, void(*run_task)(void*arg)){if(pool->shutdowm==1){//如果线程池已经关闭 return;}//初始化task* task_pool=(task*)malloc(sizeof(task));task_pool->arg=arg;task_pool->run_task=run_task;task_pool->next=NULL;//初始化完毕,开锁!pthread_mutex_lock(&pool->mutex_pool);if(pool->first==NULL){//如果是第一个线程pool->first=task_pool;pool->end=task_pool;}else{pool->end->next=task_pool;//追加新节点pool->end=task_pool;//更新链表}pool->tasksize++;pthread_cond_signal(&pool->notempty);//唤醒阻塞的线程pthread_mutex_unlock(&pool->mutex_pool);//解锁}//初始化线程
pthread_pool* pthread_init(int number){pthread_pool *pool=(pthread_pool*)malloc(sizeof(pthread_pool));if(pool==NULL){perror("malloc error");return NULL;}//初始化线程池信息pool->threadNum=number;pool->first=NULL;pool->end=NULL;pool->tasksize=0;//初始化条件变量和互斥锁pthread_mutex_init(&pool->mutex_pool,NULL);pthread_cond_init(&pool->notempty,NULL);//初始化线程表pool->threads=(pthread_t*)malloc(number*sizeof(pthread_t));//生产线程for(int i=0;i<number;i++){pthread_t tid;pthread_create(&tid,NULL,thread_work,pool);//传入你的线程池结构体}return pool;
}
//写个模拟任务吧
void run_task(void* arg){char* task_name = (char*)arg;printf("任务 %s 正在执行...\n", task_name);usleep(10);
}
//销毁线程
int pthread_destory(pthread_pool* pool){if(pool==NULL){return 0;}pool->shutdowm=1;for(int i=0;i<pool->threadNum;i++){pthread_cond_broadcast(&pool->notempty);//唤醒阻塞线程pthread_join(pool->threads[i], NULL);//分离线程printf("线程-%d正在销毁。。。\n",i);}pthread_mutex_destroy(&pool->mutex_pool);pthread_cond_destroy(&pool->notempty);//释放线程池free(pool);pool=NULL;return 0;
}int main(){pthread_pool* pool=pthread_init(5);//创建5个线程// 添加任务到线程池for (int i = 0; i < 10; i++) {char* task_name = malloc(20);snprintf(task_name, 20, "任务-%d", i + 1);addWork(pool, task_name, run_task);}usleep(100);pthread_destory(pool);return 0;      
}

我回来了,恨,因为没戴帽子被扣分了

这个代码的思路是这样的:

首先我们需要一个队列来维护我们的任务,线程池里的线程每次只要从队列里拿任务就可以了

然后创造一个结构体,存储线程池内部的信息,包括:线程的id,线程池中线程的数量,线程队列的队头、队尾,任务队列的大小,互斥锁,条件变量,线程池是否销毁的标志量

一个线程池中的线程被重复的执行任务,对于线程的操作有:初始化线程、添加任务、执行任务、销毁线程池

初始化线程:创建线程,初始化线程池相关的量

添加任务:整理线程池的队列,锁上,初始化相关内容,解锁

执行任务:整理队列,获取任务、执行,任务size--

销毁线程池:设置线程池的标志量=1,唤醒线程、分离线程、销毁锁,释放内存

再写一个模拟任务执行的函数

忘了改哪了。。好像就会看起来会舒服一点:

#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> 
//来写一个线程池,线程池需要一个存储任务的队列,线程池的容器,线程执行的任务
//任务队列创造
typedef struct task{void* arg;//指向指向函数的参数void(*run_task)(void*arg);//指向任务函数的指针struct task *next;  //next指针,指向下一个任务节点
}task;
//创建线程池
typedef struct thread_pool{task* first;//队列的开头task* end;//队列结尾int threadNum;//线程池数量int tasksize;//任务队列的大小pthread_mutex_t mutex_pool;//线程池的锁pthread_cond_t notempty;//确认队列是不是空pthread_t*threads;int shutdowm;//是否销毁线程池
}pthread_pool;
//创建接口//执行任务
void* thread_work(void*arg){pthread_pool*pool=(pthread_pool*)arg;while (1) {pthread_mutex_lock(&pool->mutex_pool);// 如果没有任务且线程池未关闭,等待任务while (pool->tasksize == 0 && !pool->shutdowm) {pthread_cond_wait(&pool->notempty, &pool->mutex_pool);}// 如果线程池关闭且任务为空,退出线程if (pool->shutdowm && pool->tasksize == 0) {pthread_mutex_unlock(&pool->mutex_pool);pthread_exit(NULL);}// 获取任务task* t = pool->first;pool->first = t->next;if (pool->first == NULL) {pool->end = NULL;}pool->tasksize--;pthread_mutex_unlock(&pool->mutex_pool);// 执行任务t->run_task(t->arg);free(t);}
}
//给线程池添加任务
void addWork(pthread_pool* pool, void* arg, void(*run_task)(void*arg)){if(pool->shutdowm==1){//如果线程池已经关闭 return;}//初始化task* task_pool=(task*)malloc(sizeof(task));task_pool->arg=arg;task_pool->run_task=run_task;task_pool->next=NULL;//初始化完毕,锁!pthread_mutex_lock(&pool->mutex_pool);if(pool->first==NULL){//如果是第一个线程pool->first=task_pool;pool->end=task_pool;}else{pool->end->next=task_pool;//追加新节点pool->end=task_pool;//更新链表}pool->tasksize++;printf("添加任务中。。。\n");pthread_cond_signal(&pool->notempty);//唤醒阻塞的线程pthread_mutex_unlock(&pool->mutex_pool);//解锁}//初始化线程
pthread_pool* pthread_init(int number){pthread_pool *pool=(pthread_pool*)malloc(sizeof(pthread_pool));if(pool==NULL){perror("malloc error");return NULL;}//初始化线程池信息pool->threadNum=number;pool->first=NULL;pool->end=NULL;pool->tasksize=0;//初始化条件变量和互斥锁pthread_mutex_init(&pool->mutex_pool,NULL);pthread_cond_init(&pool->notempty,NULL);//初始化线程表pool->threads=(pthread_t*)malloc(number*sizeof(pthread_t));//生产线程for(int i=0;i<number;i++){printf("线程%d初始化中。。。\n",i+1);pthread_create(&pool->threads[i],NULL,thread_work,pool);//传入你的线程池结构体}return pool;
}
//写个模拟任务吧
void run_task(void* arg){char* task_name = (char*)arg;printf("任务 %s 正在执行...\n", task_name);usleep(10);
}
//销毁线程
int pthread_destory(pthread_pool* pool){if(pool==NULL){return 0;}pool->shutdowm=1;for(int i=0;i<pool->threadNum;i++){pthread_cond_broadcast(&pool->notempty);//唤醒阻塞线程pthread_join(pool->threads[i], NULL);//分离线程printf("线程-%d正在销毁。。。\n",i+1);}pthread_mutex_destroy(&pool->mutex_pool);pthread_cond_destroy(&pool->notempty);free(pool->threads);//释放线程池free(pool);pool=NULL;return 0;
}int main(){pthread_pool* pool=pthread_init(5);//创建5个线程// 添加任务到线程池for (int i = 0; i < 10; i++) {char* task_name = malloc(20);snprintf(task_name, 20, "任务-%d", i + 1);addWork(pool, task_name, run_task);}usleep(1000);pthread_destory(pool);return 0;      
}

为什么要使用线程池
频繁的进行进程的创建与销毁将带来很多开销。不但如此,进程间频繁的切换也将减低 CPU 的利用率。

如果能复用之前创建的进程,而不是为每个并发任务创建一个进程,能有效降低进程创建与销毁的开销并减少进程间切换,从而减少对 CPU 资源的浪费。

虽然线程创建与销毁的代价小于进程创建与销毁,隶属同一进程的线程间切换的代价也小于进程间切换,但复用之前创建的线程,也能有效降低线程创建与销毁的开销并减少线程间切换,从而减少对 CPU 资源的浪费。
当任务很多的时,我们就可以调用线程池,从而有效的的对CPU资源的浪费。

线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。

什么时候会用到线程池技术:

单个任务小而任务量巨大,例如访问一个web网页、一个点击量大的网站;而对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了

总体的设计流程就是:

创建固定数量的线程池,从任务队列中获取任务对象

找到任务对象并执行

维护任务队列


http://www.ppmy.cn/ops/130251.html

相关文章

【数据结构 | C语言】单身狗进化

这一天晚上,弯通又做梦了,并且梦到了一个帅气的男孩纸!这个男孩给了弯通一个数字 n。男孩离开前告诉弯通,n!(n 的阶乘)的位数就是距离弯通脱单的天数。矜持的弯通想知道自己还有多久能脱单,快写个程序帮助他! 输入格式:输入第一行为一个正整数 n(1<=n<=25000)…

考个计算机视觉专家,惊艳所有人!

为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国务院印发《关于“十四五”数字经济发展规划》等有关工作的部署要求&#xff0c;深入实施人才强国战略和创新驱动发展战略&#xff0c;加强全国数字化人才队伍建设&#xff0c;持续推进人工智能从业人员…

git 切换分支

要在 Git 中切换分支&#xff0c;您可以使用以下命令&#xff1a; 查看当前分支及其所在分支 git branch切换到另一个分支 git checkout branch_name其中 branch_name 是您要切换到的分支名称。 另外&#xff0c;您可以通过以下命令创建一个新的分支并立即切换到该分支&#x…

2-132基于matlab的一种牛头刨床的运动仿真以及运动学分析

基于matlab的一种牛头刨床的运动仿真以及运动学分析&#xff0c;通过运动公式及参数设置得到角位移和位移曲线&#xff0c;角速度和速度曲线&#xff0c;角加速度和加速度曲线。输出机构运动简图及动态可视化图。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#…

多源BFS问题(4)_地图分析

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 多源BFS问题(4)_地图分析 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1.…

webrtc agc2实现原理

WebRTC的AGC2&#xff08;自适应增益控制器&#xff09;是一种用于音频处理的算法&#xff0c;可以根据输入信号的强度自动调整增益&#xff0c;使输出信号的音量保持稳定。其详细原理如下&#xff1a; 噪声估计 首先&#xff0c;AGC2需要对输入信号中的噪声进行估计&#xff…

【AIGC】深入探索『后退一步』提示技巧:激发ChatGPT的智慧潜力

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;“后退一步”技巧介绍技巧目的 &#x1f4af;“后退一步”原理“后退一步”提示技巧与COT和TOT的对比实验验证 &#x1f4af;如何应用“后退一步”策略强调抽象思考引导提…

Sublime Text 的PHP格式化插件phpfmt 的 setting 配置参数说明

phpfmt.sublime-settings 是 Sublime Text 中 phpfmt 插件的配置文件&#xff0c;用于定义代码格式化的各种参数。以下是一些常见的配置参数及其说明&#xff1a; 1、version 指定配置文件的版本&#xff0c;根据 phpfmt 插件的版本&#xff0c;此值可能有所不同。 2、php_b…