news 2026/6/10 19:51:04

多线程之线程池

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
多线程之线程池

文章目录

  • 线程池的优点
  • 线程池的四大核心(组件)
    • 任务队列
    • 工作线程
    • 管理者
    • 控制开关
  • 实现步骤
    • 创建线程池
    • 工作线程的行为
    • 添加任务
    • 销毁线程池
  • 关键数据结构
  • 示例
  • 注意事项
  • 如果每个任务创建新线程,任务结束即销毁线程,资源的消耗和开销也不小
  • 固定数量的线程处理多个任务,实现线程复用

线程池的优点

  • 避免频繁创建/销毁线程的开销
  • 控制并发线程数量,避免资源耗尽
  • 提高响应速度(任务无需等待线程创建)

线程池的四大核心(组件)

  • 任务队列(待办清单)
  • 工作线程(员工团队)
  • 管理者(协调工具)
  • 控制开关

任务队列

  • 使用链表实现的 FIFO 队列
  • 每个任务包含:
    • 任务函数指针(要执行的操作)
    • 参数(执行所需数据)
    • 指向下一个任务的指针
structTask{void(*function)(void*);// 任务函数(做什么)void*arg;// 参数(用什么做)structTask*next;// 下一个任务};

工作线程

  • 固定数量的线程(如 CPU 核心数 × 2)
  • 每个线程循环:等待任务 → 取出任务 → 执行任务
whileTrue:等待任务->取出任务->执行任务

管理者

  • 互斥锁(mutex):保护共享资源(任务队列)
  • 条件变量(cond):线程间通信,通知新任务到达

控制开关

  • shutdown 标志:安全关闭信号,优雅终止线程池

实现步骤

  • 第一步:创建线程池
  • 第二步:工作线程的行为
  • 第三步:添加任务
  • 第四步:销毁线程池

创建线程池

ThreadPool*thread_pool_create(){// 分配内存// 初始化互斥锁和条件变量// 初始化任务队列// 设置 shutdown 标志为 0// 创建固定数量的工作线程}

工作线程的行为

void*worker(void*arg){while(1){上锁;while(无任务且不关闭){等待条件变量;}if(需要关闭)退出;取出任务;解锁;执行任务;释放任务内存;}}

添加任务

intthread_pool_add_task(ThreadPool*pool,函数指针,参数){// 创建新任务节点// 上锁// 加入队列尾部// 发送条件信号// 解锁}

销毁线程池

voidthread_pool_destroy(ThreadPool*pool){// 设置 shutdown 标志为 1// 广播通知所有线程// 等待所有线程退出// 清理剩余任务// 销毁锁和条件变量// 释放内存}

关键数据结构

typedefstructTask{void(*function)(void*);// 任务函数void*arg;// 参数structTask*next;// 下一个任务}task_t;typedefstructThreadPool{pthread_mutex_tmutex;// 互斥锁pthread_cond_tcond;// 条件变量pthread_tthreads[THREAD_NUM];// 线程数组task_t*task_head;// 任务队列头task_t*task_tail;// 任务队列尾intshutdown;// 关闭标志}tpool_t;

示例

#include<pthread.h>#include<stdlib.h>#include<stdio.h>#include<unistd.h>#defineTHREAD_NUM4//任务队列typedefstructTask{void(*function)(void*);void*arg;structTask*next;}task_t;//线程池结构体typedefstructthread_pool{pthread_mutex_tmutex;pthread_cond_tcond;pthread_ttid[THREAD_NUM];task_t*task_head;task_t*task_tail;intshutdown;//线程池的开关,0代表使用,1代表销毁}tpool_t;//工作线程void*worker(void*arg){tpool_t*pool=(tpool_t*)arg;while(1){//1. 锁定临界资源pthread_mutex_lock(&pool->mutex);//2. 等待任务while(pool->task_head==NULL&&!pool->shutdown){pthread_cond_wait(&pool->cond,&pool->mutex);}//3. 检查线程开关if(pool->shutdown){pthread_mutex_unlock(&pool->mutex);pthread_exit(NULL);}//4. 取出任务task_t*task=pool->task_head;if(task==NULL){pthread_mutex_unlock(&pool->mutex);continue;}//5. 列新任务队列pool->task_head=task->next;if(pool->task_head==NULL){pool->task_tail=NULL;}//6. 解锁pthread_mutex_unlock(&pool->mutex);//7. 执行任务task->function(task->arg);free(task);}returnNULL;}//创建线程池tpool_t*thread_pool_init(){//1. 为线程池结构体申请内存tpool_t*pool=malloc(sizeof(tpool_t));if(pool==NULL){returnNULL;}//2. 初始化互斥量,条件变量pthread_mutex_init(&pool->mutex,NULL);pthread_cond_init(&pool->cond,NULL);//3. 初始化队列pool->task_head=NULL;pool->task_tail=NULL;//4. 初始化线程池的开关pool->shutdown=0;//5. 创建工作线程for(inti=0;i<THREAD_NUM;i++){pthread_create(&pool->tid[i],NULL,worker,pool);}returnpool;}//添加任务队列 添加成功返回0,失败返回 -1intthread_pool_add_task(tpool_t*pool,void(*function)(void*),void*arg){//1. 创建新任务task_t*new_task=malloc(sizeof(task_t));if(new_task==NULL){return-1;}new_task->function=function;new_task->arg=arg;new_task->next=NULL;//2. 锁定临界资源pthread_mutex_lock(&pool->mutex);//3. 加入队列if(pool->task_tail==NULL){pool->task_head=pool->task_tail=new_task;}else{pool->task_tail->next=new_task;pool->task_tail=new_task;}//4. 通知工作线程,并解锁pthread_cond_signal(&pool->cond);pthread_mutex_unlock(&pool->mutex);return0;}//销毁线程池intthread_pool_destroy(tpool_t*pool){//1. 关闭线程池pthread_mutex_lock(&pool->mutex);pool->shutdown=1;pthread_mutex_unlock(&pool->mutex);//2. 唤醒所有等待的线程pthread_cond_broadcast(&pool->cond);//3. 等待所有线程退出for(inti=0;i<THREAD_NUM;i++){pthread_join(pool->tid[i],NULL);}//4. 释放各种资源task_t*p=pool->task_head;while(p!=NULL){task_t*temp=p;p=p->next;free(temp);}pthread_mutex_destroy(&pool->mutex);pthread_cond_destroy(&pool->cond);free(pool);return0;}/*线程池功能测试*/voidcook(void*arg){intorder_id=*(int*)arg;printf("厨师%lu 开始制作订单%d\n",pthread_self(),order_id);sleep(1);// 模拟烹饪时间printf("订单%d 完成!\n",order_id);}intmain(intargc,constchar*argv[]){// 创建线程池tpool_t*pool=thread_pool_init();if(pool==NULL){}// 添加任务intorders[10];for(inti=0;i<10;i++){orders[i]=1000+i;thread_pool_add_task(pool,cook,&orders[i]);}sleep(4);// 销毁线程池thread_pool_destroy(pool);return0;}

注意事项

  • 任务函数设计适合:独立计算、文件操作、网络请求,避免长时间阻塞操作(如等待用户输入)
  • 线程数量设置经验公式:CPU 核心数 × 2
  • 过多线程会增加上下文切换开销
  • 访问共享资源(队列)前必须加锁
  • 使用条件变量进行线程间通信
  • 确保销毁时所有资源被正确释放
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 8:03:03

Java基础进阶-水仙花数

/* 功能&#xff1a;求水仙花数&#xff0c;打印并统计总个数。 思路&#xff1a; 水仙花数是定义范围100-999&#xff0c;满足每个位上的数子的3次方相加和等于这个数 第一步&#xff1a;循环遍历数据范围 第二步&#xff1b;取出当前数字的个位&#xff0c;十位&#xff0c;百…

作者头像 李华
网站建设 2026/6/10 5:57:08

【论文精读】-Graph-Grounded Pre-training and Prompting

家人们&#xff0c;主播又回来啦&#xff0c;这一周主播比较忙&#xff0c;所以就只认认真真精读了这一篇论文。主播这也是第一次使用提问法&#xff0c;讲这篇文章里面究极的一些问题给弄明白了&#xff0c;这也是很好的一点。话不多说&#xff0c;我们来一起看看这篇文章吧&a…

作者头像 李华
网站建设 2026/6/10 9:28:39

大模型产品经理课程(非常详细)大模型入门到精通,收藏这篇就够了

根据《2024年中国AI大模型场景探索及产业应用调研报告》&#xff0c;当前整体AI大模型行业仍然处于萌芽期&#xff0c;但市场规模增速较快。2023年我国AI大模型行业规模达到了147亿元&#xff0c;近三年复合增速高达114%。预计2024年&#xff0c;该市场规模将进一步增长至216亿…

作者头像 李华
网站建设 2026/6/10 9:27:36

IPV6公网暴露下的OPENWRT防火墙安全设置(只允许访问局域网中指定服务器指定端口其余拒绝)

首先是防火墙的常规配置和区域配置 标的有点乱但是选项含义都做了解释&#xff0c;看不懂可以直接按图抄作业。 其次是对需要访问的端口做访问放通 情况1 DDNS位于openwrt网关上&#xff0c;外网访问openwrt&#xff0c;通过端口转发访问内部服务器。此情况需要设置端口转发。 …

作者头像 李华
网站建设 2026/6/9 20:03:33

Java进阶之泛型

泛型 (Generics) 定义 泛型&#xff1a;允许在定义类、接口和方法时使用类型参数&#xff0c;从而在编译时捕获类型错误&#xff0c;提高代码的类型安全性和复用性。 主要用途 类型安全&#xff1a;避免类型转换错误&#xff0c;编译时检查类型安全。代码复用&#xff1a;通过泛…

作者头像 李华
网站建设 2026/6/10 9:26:45

Java进阶-思维导图

文章目录 一、Static、继承、权限修饰符二、final、抽象类、接口三、多态、内部类、枚举四、常用API、时间API、正则表达式五、数据结构、LIST集合、可变参数、泛型六、set集合、迭代器、增强for七、map、排序&查找八、异常、多线程九、多线程续、JDK1.8新特性十、File、递…

作者头像 李华