线程池框图

C语言线程池详解:从基础到实现

通俗理解线程池

想象你开了一家快递站,每天要处理很多包裹派送:

  1. 没有线程池​:每来一个包裹就雇一个新快递员,送完就解雇
    • 问题:频繁招聘解雇成本高(线程创建销毁开销大)
  2. 有线程池​:固定雇佣5个快递员,包裹来了就分配给空闲的快递员
    • 优点:快递员复用,效率高,管理方便

线程池就是这样的"快递员管理系统",预先创建一组线程,有任务时分配给空闲线程执行。

完整C语言线程池实现(带详细注释)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>#define THREAD_NUM 5  // 线程池中线程数量// 任务结构体(相当于快递站的"包裹")
typedef struct {void (*function)(void *);  // 任务函数指针void *arg;                 // 函数参数
} Task;// 线程池结构体(相当于"快递站")
typedef struct {Task *task_queue;          // 任务队列(存放待处理的任务)int queue_capacity;        // 队列容量int queue_size;            // 当前队列中任务数量int queue_front;           // 队首索引int queue_rear;            // 队尾索引pthread_t *threads;        // 工作线程数组(相当于"快递员")pthread_mutex_t mutex;    // 互斥锁,保护任务队列pthread_cond_t cond;       // 条件变量,线程等待信号int shutdown;              // 线程池关闭标志
} ThreadPool;// 创建线程池
ThreadPool* thread_pool_create(int capacity) {ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));// 初始化任务队列pool->queue_capacity = capacity;pool->task_queue = (Task *)malloc(sizeof(Task) * capacity);pool->queue_size = 0;pool->queue_front = 0;pool->queue_rear = 0;// 初始化线程数组pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * THREAD_NUM);// 初始化互斥锁和条件变量pthread_mutex_init(&pool->mutex, NULL);pthread_cond_init(&pool->cond, NULL);// 设置线程池运行状态pool->shutdown = 0;// 创建工作线程for (int i = 0; i < THREAD_NUM; i++) {pthread_create(&pool->threads[i], NULL, worker, (void *)pool);}return pool;
}// 工作线程函数(相当于"快递员的工作流程")
void* worker(void* arg) {ThreadPool *pool = (ThreadPool *)arg;while (1) {pthread_mutex_lock(&pool->mutex);  // 加锁保护任务队列// 当任务队列为空且线程池未关闭时,线程等待while (pool->queue_size == 0 && !pool->shutdown) {pthread_cond_wait(&pool->cond, &pool->mutex);  // 等待条件变量}// 如果线程池已关闭且任务已处理完,线程退出if (pool->shutdown && pool->queue_size == 0) {pthread_mutex_unlock(&pool->mutex);pthread_exit(NULL);}// 从任务队列中取出一个任务Task task;task.function = pool->task_queue[pool->queue_front].function;task.arg = pool->task_queue[pool->queue_front].arg;// 更新队列状态pool->queue_front = (pool->queue_front + 1) % pool->queue_capacity;pool->queue_size--;pthread_mutex_unlock(&pool->mutex);  // 解锁// 执行任务(快递员开始派送包裹)printf("Thread %lu start working...\n", pthread_self());task.function(task.arg);  // 调用任务函数printf("Thread %lu finish work!\n", pthread_self());}return NULL;
}// 添加任务到线程池
void thread_pool_add(ThreadPool *pool, void (*func)(void *), void *arg) {pthread_mutex_lock(&pool->mutex);  // 加锁保护任务队列// 如果队列已满,等待(这里简单处理,实际可以扩容或返回错误)while (pool->queue_size == pool->queue_capacity && !pool->shutdown) {pthread_cond_wait(&pool->cond, &pool->mutex);}if (pool->shutdown) {pthread_mutex_unlock(&pool->mutex);return;}// 添加任务到队尾pool->task_queue[pool->queue_rear].function = func;pool->task_queue[pool->queue_rear].arg = arg;pool->queue_rear = (pool->queue_rear + 1) % pool->queue_capacity;pool->queue_size++;pthread_cond_signal(&pool->cond);  // 唤醒一个等待的线程pthread_mutex_unlock(&pool->mutex);  // 解锁
}// 销毁线程池
void thread_pool_destroy(ThreadPool *pool) {if (pool == NULL) return;// 设置关闭标志pool->shutdown = 1;// 唤醒所有等待的线程pthread_cond_broadcast(&pool->cond);// 等待所有线程退出for (int i = 0; i < THREAD_NUM; i++) {pthread_join(pool->threads[i], NULL);}// 释放资源free(pool->threads);free(pool->task_queue);pthread_mutex_destroy(&pool->mutex);pthread_cond_destroy(&pool->cond);free(pool);
}// 示例任务函数1
void task_function1(void *arg) {int num = *(int *)arg;printf("Task1 processing number: %d\n", num);sleep(1);  // 模拟耗时操作
}// 示例任务函数2
void task_function2(void *arg) {char *str = (char *)arg;printf("Task2 processing string: %s\n", str);sleep(2);  // 模拟耗时操作
}int main() {// 创建线程池,任务队列容量为10ThreadPool *pool = thread_pool_create(10);// 添加任务到线程池for (int i = 0; i < 10; i++) {int *num = (int *)malloc(sizeof(int));*num = i;thread_pool_add(pool, task_function1, (void *)num);}// 添加不同类型的任务char *str = "Hello ThreadPool";thread_pool_add(pool, task_function2, (void *)str);// 等待所有任务完成sleep(5);// 销毁线程池thread_pool_destroy(pool);return 0;
}

关键组件详细解释

1. 任务队列(Task Queue)

typedef struct {void (*function)(void *);  // 函数指针void *arg;                 // 函数参数
} Task;
  • 作用​:存储待执行的任务
  • 原理​:使用环形队列实现,避免频繁内存分配
  • 操作​:
    • 队尾添加任务
    • 队首取出任务

2. 线程池管理(ThreadPool)

typedef struct {Task *task_queue;         // 任务队列int queue_capacity;       // 队列容量int queue_size;           // 当前任务数// ...其他成员
} ThreadPool;
  • 作用​:管理线程和任务队列
  • 关键成员​:
    • threads:工作线程数组
    • mutex:保护任务队列的互斥锁
    • cond:线程间通信的条件变量

3. 工作线程(Worker Thread)

void* worker(void* arg) {while (1) {// 1. 加锁并检查任务队列// 2. 无任务时等待条件变量// 3. 取出任务并执行// 4. 解锁}
}
  • 工作流程​:
    1. 检查任务队列
    2. 无任务则等待
    3. 有任务则取出执行
    4. 循环处理

4. 任务添加(thread_pool_add)

void thread_pool_add(ThreadPool *pool, void (*func)(void *), void *arg) {// 1. 加锁// 2. 检查队列状态// 3. 添加任务到队列// 4. 唤醒一个等待线程// 5. 解锁
}
  • 作用​:向线程池提交新任务
  • 关键点​:
    • 队列满时等待
    • 添加后唤醒工作线程

5. 线程池销毁(thread_pool_destroy)

void thread_pool_destroy(ThreadPool *pool) {// 1. 设置关闭标志// 2. 唤醒所有线程// 3. 等待线程退出// 4. 释放资源
}
  • 作用​:安全关闭线程池
  • 关键点​:
    • 先通知所有线程
    • 等待线程自然退出

线程池工作流程图

主线程:[创建线程池] → [添加任务] → [销毁线程池]|               |↓               ↓
任务队列: [任务1][任务2][任务3]...|↓
工作线程:[线程1取任务] → [执行] → [取下一个任务][线程2取任务] → [执行] → [取下一个任务]...

为什么需要这些机制?

  1. 互斥锁(mutex)​​:

    • 防止多个线程同时访问任务队列导致数据混乱
  2. 条件变量(cond)​​:

    • 当任务队列为空时,让工作线程休眠等待
    • 当有新任务时唤醒线程,避免忙等待
  3. 环形队列​:

    • 高效利用内存,避免频繁内存分配
    • 先进先出(FIFO)的任务处理顺序
  4. 线程复用​:

    • 避免频繁创建销毁线程的开销
    • 控制并发数量,防止系统过载

实际应用场景

  1. 网络服务器​:处理大量客户端请求
  2. 文件处理​:批量处理大量文件
  3. 数据计算​:并行计算任务
  4. GUI应用​:后台耗时任务处理

扩展改进建议

  1. 动态调整线程数​:根据负载自动增减线程
  2. 任务优先级​:支持高优先级任务插队
  3. 任务取消​:支持取消已提交但未执行的任务
  4. 超时机制​:设置任务执行超时时间
  5. 任务结果获取​:提供获取任务执行结果的机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918322.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918322.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918322.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt-Advanced-Docking-System

直译一下 &#xff1a; 先进的停靠系统 github: mfreiholz/Qt-Advanced-Docking-System: Advanced Docking System for Qt 这是这个项目的起源 这个最后一次更新&#xff1a; githubuser0xFFFF/Qt-Advanced-Docking-System: Advanced Docking System for Qt 这是另一个人复刻…

湖南(源点咨询)市场调研 如何在行业研究中快速有效介入 中篇

我们接着起头篇来说迈克尔波特认为一个行业内存在着五种基本竞争力量&#xff0c;即潜在入侵者、替代产品、供方、需方以及行业内现有竞争者。如附图&#xff1a;即&#xff1a;同行业内现有竞争者的竞争能力、潜在竞争者进入的能力、替代品的替代能力、供应商的讨价还价能力、…

【无标题】消息队列(Message Queue)是一种**进程间通信(IPC)机制

消息队列&#xff08;Message Queue&#xff09;是一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;它允许进程通过在队列中添加和读取消息来交换数据。与管道&#xff08;命名/匿名&#xff09;相比&#xff0c;消息队列具有结构化消息、异步通信和消息持久化等特点…

mac中多版本JDK配置和切换

下载 从jdk官网下载即可&#xff0c;找到自己要用的版本。 官网&#xff1a;https://www.oracle.com/java/technologies/downloads/#jdk21-mac 我这里下载的jdk1.8和21。 根据自己芯片下载&#xff0c;一般都是m芯片。下载好后&#xff0c;点击&#xff0c;一直下一步就行&…

【JVM】流程汇总

【JVM】流程汇总【一】编译过程和内存分布【1】案例程序&#xff1a;简单的 Java 类【2】Java 编译过程&#xff1a;从.java到.class&#xff08;1&#xff09;编译命令&#xff08;2&#xff09;编译结果&#xff08;3&#xff09;字节码的作用【3】Java 运行过程&#xff1a;…

专业MP3瘦身工具WinMP3Shrink 1.1,绿色单文件,极速压缩

[软件名称]: 专业MP3瘦身工具WinMP3Shrink 1.1 [软件大小]: 1.1 MB [软件大小]: 夸克网盘 | 百度网盘 软件介绍 WinMP3Shrink 是一款免费的 MP3 压缩软件&#xff0c;能够有效减少 MP3 文件的体积&#xff0c;同时还能增强音质。即使不重新编码&#xff0c;通过移除保留空间…

LeetCode 每日一题 2025/8/4-2025/8/10

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录8/4 904. 水果成篮8/5 3477. 水果成篮 II8/6 3479. 水果成篮 III8/7 3363. 最多可收集的水果数目8/8 808. 分汤8/9 231. 2 的幂8/10 869. 重新排序得到 2 的幂8/4 904. 水果…

Python爬虫实战:研究Ruia框架,构建博客园文章采集系统

1. 引言 1.1 研究背景与意义 在数字化时代,数据已成为驱动科技创新与产业升级的核心生产要素。互联网作为全球最大的信息载体,蕴含着亿级结构化、半结构化与非结构化数据,这些数据在商业决策、学术研究、公共服务等领域具有不可替代的价值。网络爬虫技术作为自动获取网络公…

Office安装使用?借助Ohook开源工具?【图文详解】微软Office产品

一、问题背景 很多用户在使用 Office 软件一段时间后&#xff0c;会遇到以下问题。 二、解决方案 Ohook 是 Office 独有的可用方式&#xff0c;源自 GitHub 上的开源项目&#xff0c;代码开源&#xff08;开源地址&#xff1a;https://github.com/asdcorp/ohook&#xff09;。 …

LeetCode简单题 - 学习

力扣题库 - 简单题 - 仅记录学习 来源地址&#xff1a; 力扣 (LeetCode) 全球极客挚爱的技术成长平台 1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你…

Android Camera 打开和拍照APK源码

完整下载路径: 【免费】AndroidcameraAPK完整源码(包括打开摄像头和拍照保存功能)Android10验证可完整运行资源-CSDN下载 效果: 源码: package com.example.mycamera;import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appco…

【系统分析师】软件需求工程——第11章学习笔记(上)

软件需求工程是包括创建和维护软件需求文档所必需的一切活动的过程。可分为两大工作&#xff1a;需求开发需求获取需求分析需求定义&#xff08;编写需求规格说明书&#xff09;需求验证需求管理定义需求基线处理需求变更需求跟踪在需求开发阶段需要确定软件所期望的用户类型&a…

机器学习第七课之支持向量机SVM

目录 简介&#xff1a; 一、什么是支持向量机 二、如何选取最佳的超平面 1.超平面方程 (优化目标) 2.如何寻找最优的超平面 3.举例分析 4.软间隔​编辑 三、核函数 1举例 2常用核函数 3.多项式核函数 4.高斯核函数: 四、svm的优缺点 五、支持向量机的API 六、案例…

P3232 [HNOI2013] 游走,solution

原题&#xff1a; link&#xff0c;点击这里喵。 题意&#xff1a; 给定一个 nnn 个点 mmm 条边的无向连通图&#xff0c;图无重边和自环&#xff0c;顶点从 111 编号到 nnn&#xff0c;边从 111 编号到 mmm。 小 Z 在该图上进行随机游走&#xff0c;初始时小 Z 在 111 号顶…

Docker容器部署discuz论坛与线上商城

准备 关闭防火墙&#xff0c;上下文[rootdocker ~]# systemctl disable --now firewalld[rootdocker ~]# setenforce 0下载应用yum remove runc -y ### rocky8才需要yum install -y yum-utils yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/cento…

Linux入门指南:26个基础命令全解析

目录 一.基础概念与入门 1.Linux操作系统简介 2.终端与shell的基本概念 3.命令行界面的优势 二.基础指令 1.whoami ​2.useradd/userdel/passwd ​3.pwd ​4.ls ​5.cd 6.touch 7.mkdir 8.tree 9.rmdir/rm 10.man 11.cp 12.mv 13.cat 14.le…

【后端】Java 8 特性 `User::getId` 语法(方法引用)介绍

文章目录核心概念解析&#xff1a;方法引用的四种类型&#xff1a;关键特性&#xff1a;使用场景推荐&#xff1a;何时避免使用&#xff1a;性能说明&#xff1a;在 Java 中&#xff0c; User::getId 是一种称为 方法引用&#xff08;Method Reference&#xff09; 的语法糖&a…

基于BP与CNN的图像分类模型构建、超参数优化及性能对比研究​

一、实验目的实验目标构建基于神经网络模型的数据分析与模式识别框架&#xff0c;探明神经网络在大数据分析中的意义。实验任务构建基于深度 BP 神经网络与卷积神经网络的数据分析与模式识别框架&#xff0c;将数据集 MNIST 与 CIFAR-10 分别在两种模型中训练&#xff0c;并比较…

HarmonyOS应用开发-低代码开发登录页面(超详细)

本篇文章我来手把手教大家做一个HarmonyOS 应用的登录页面&#xff0c;逐步讲解&#xff0c;非常细致&#xff0c;百分百能学会&#xff0c;并提供全部源码。页面使用 DevEco Studio 的低代码开发。 通过本文的实践经验&#xff0c;我想告诉大家&#xff0c; HarmonyOS 应用开发…

AJAX与axios框架

文章目录前言案例跨域访问总结❗前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 通过 ajax 进行前后端交互 案例 此项目用到了javaweb知识 首先创建JavaWeb项目编写代码&#xff1a; package ajax;import java.io.IOException; import java.util.Arr…