news 2026/8/30 7:20:49

多线程之线程池

作者头像

张小明

前端开发工程师

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/8/29 8:17:58

救命神器!9个AI论文网站测评:本科生毕业论文全攻略

救命神器&#xff01;9个AI论文网站测评&#xff1a;本科生毕业论文全攻略 学术写作新选择&#xff1a;AI论文网站测评全解析 在当前高校教育日益重视科研能力的背景下&#xff0c;本科生在撰写毕业论文时面临诸多挑战&#xff0c;如选题困难、资料查找繁琐、格式规范不熟悉等。…

作者头像 李华
网站建设 2026/8/27 10:28:08

通信协议仿真:蓝牙协议仿真_(6).蓝牙网络拓扑

蓝牙网络拓扑 1. 蓝牙网络基础 蓝牙网络拓扑是指蓝牙设备在无线通信网络中的组织和连接方式。理解蓝牙网络的基本概念和拓扑结构对于进行蓝牙协议仿真至关重要。蓝牙网络可以分为两种主要类型&#xff1a;基础模式&#xff08;Basic Rate/Enhanced Data Rate, BR/EDR&#xff0…

作者头像 李华
网站建设 2026/8/29 7:21:23

通信协议仿真:蓝牙协议仿真_(9).蓝牙仿真案例分析

蓝牙仿真案例分析 在上一节中&#xff0c;我们已经介绍了蓝牙协议的基本概念和结构。本节将通过具体的案例来分析蓝牙协议的仿真过程&#xff0c;帮助读者更好地理解如何在实际开发中应用蓝牙仿真技术。我们将从以下几个方面进行详细的分析&#xff1a; 蓝牙设备连接仿真蓝牙数…

作者头像 李华
网站建设 2026/8/26 20:48:39

Java实战:Spring Boot application.yml配置文件详解

本文将详细介绍Spring Boot application.yml 配置文件的使用和配置项。我们将探讨 application.yml 文件的基本概念&#xff0c;以及如何使用它来配置Spring Boot应用程序的各个方面。此外&#xff0c;我们将通过具体的示例来展示如何配置不同的Spring Boot组件&#xff0c;如数…

作者头像 李华
网站建设 2026/8/29 7:21:17

51单片机__LED相关

51单片机__LED相关 单片机介绍 单片机&#xff0c;英文Micro Controller Unit&#xff0c;简称MCU 内部集成了CPU、RAM、ROM、定时器、中断系统、通讯接口等一系列电脑的常用硬件功能 单片机的任务是信息采集&#xff08;依靠传感器&#xff09;、处理&#xff08;依靠CPU&…

作者头像 李华