当前位置: 首页 > news >正文

【Linux】线程池

🎇Linux:


  • 博客主页:一起去看日落吗
  • 分享博主的在Linux中学习到的知识和遇到的问题
  • 博主的能力有限,出现错误希望大家不吝赐教
  • 分享给大家一句我很喜欢的话: 看似不起波澜的日复一日,一定会在某一天让你看见坚持的意义,祝我们都能在鸡零狗碎里找到闪闪的快乐🌿🌞🐾。

在这里插入图片描述

🍁 🍃 🍂 🌿


目录

  • 🌿1. Linux线程池
    • 🍃1.1 线程池的概念
    • 🍃1.2 线程池的优点
    • 🍃1.3 线程池的应用场景
    • 🍃1.4 线程池的实现

🌿1. Linux线程池

🍃1.1 线程池的概念

线程池是一种线程使用模式。

线程过多会带来调度开销,进而影响缓存局部和整体性能,而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。


🍃1.2 线程池的优点

  • 线程池避免了在处理短时间任务时创建与销毁线程的代价。
  • 线程池不仅能够保证内核充分利用,还能防止过分调度。

注意: 线程池中可用线程的数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。


🍃1.3 线程池的应用场景

线程池常见的应用场景如下:

  1. 需要大量的线程来完成任务,且完成任务的时间比较短。
  2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。

相关解释:

  • 像Web服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。
  • 对于长时间的任务,比如Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
  • 突发性大量客户请求,在没有线程池的情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,但短时间内产生大量线程可能使内存到达极限,出现错误。

🍃1.4 线程池的实现

下面我们实现一个简单的线程池,线程池中提供了一个任务队列,以及若干个线程(多线程)。

在这里插入图片描述

  • 线程池中的多个线程负责从任务队列当中拿任务,并将拿到的任务进行处理。
  • 线程池对外提供一个Push接口,用于让外部线程能够将任务Push到任务队列当中。
#pragma once#include <iostream>
#include <unistd.h>
#include <queue>
#include <pthread.h>#define NUM 5//线程池
template<class T>
class ThreadPool
{
private:bool IsEmpty(){return _task_queue.size() == 0;}void LockQueue(){pthread_mutex_lock(&_mutex);}void UnLockQueue(){pthread_mutex_unlock(&_mutex);}void Wait(){pthread_cond_wait(&_cond, &_mutex);}void WakeUp(){pthread_cond_signal(&_cond);}
public:ThreadPool(int num = NUM): _thread_num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}//线程池中线程的执行例程static void* Routine(void* arg){pthread_detach(pthread_self());ThreadPool* self = (ThreadPool*)arg;//不断从任务队列获取任务进行处理while (true){self->LockQueue();while (self->IsEmpty()){self->Wait();}T task;self->Pop(task);self->UnLockQueue();task.Run(); //处理任务}}void ThreadPoolInit(){pthread_t tid;for (int i = 0; i < _thread_num; i++){pthread_create(&tid, nullptr, Routine, this); //注意参数传入this指针}}//往任务队列塞任务(主线程调用)void Push(const T& task){LockQueue();_task_queue.push(task);UnLockQueue();WakeUp();}//从任务队列获取任务(线程池中的线程调用)void Pop(T& task){task = _task_queue.front();_task_queue.pop();}
private:std::queue<T> _task_queue; //任务队列int _thread_num; //线程池中线程的数量pthread_mutex_t _mutex;pthread_cond_t _cond;
};

为什么线程池中需要有互斥锁和条件变量?

线程池中的任务队列是会被多个执行流同时访问的临界资源,因此我们需要引入互斥锁对任务队列进行保护。

线程池当中的线程要从任务队列里拿任务,前提条件是任务队列中必须要有任务,因此线程池当中的线程在拿任务之前,需要先判断任务队列当中是否有任务,若此时任务队列为空,那么该线程应该进行等待,直到任务队列中有任务时再将其唤醒,因此我们需要引入条件变量。

当外部线程向任务队列中Push一个任务后,此时可能有线程正处于等待状态,因此在新增任务后需要唤醒在条件变量下等待的线程。

注意:

  • 当某线程被唤醒时,其可能是被异常或是伪唤醒,或者是一些广播类的唤醒线程操作而导致所有线程被唤醒,使得在被唤醒的若干线程中,只有个别线程能拿到任务。此时应该让被唤醒的线程再次判断是否满足被唤醒条件,所以在判断任务队列是否为空时,应该使用while进行判断,而不是if。
  • pthread_cond_broadcast函数的作用是唤醒条件变量下的所有线程,而外部可能只Push了一个任务,我们却把全部在等待的线程都唤醒了,此时这些线程就都会去任务队列获取任务,但最终只有一个线程能得到任务。一瞬间唤醒大量的线程可能会导致系统震荡,这叫做惊群效应。因此在唤醒线程时最好使用pthread_cond_signal函数唤醒正在等待的一个线程即可。
  • 当线程从任务队列中拿到任务后,该任务就已经属于当前线程了,与其他线程已经没有关系了,因此应该在解锁之后再进行处理任务,而不是在解锁之前进行。因为处理任务的过程可能会耗费一定的时间,所以我们不要将其放到临界区当中。
  • 如果将处理任务的过程放到临界区当中,那么当某一线程从任务队列拿到任务后,其他线程还需要等待该线程将任务处理完后,才有机会进入临界区。此时虽然是线程池,但最终我们可能并没有让多线程并行的执行起来。

为什么线程池中的线程执行例程需要设置为静态方法?

使用pthread_create函数创建线程时,需要为创建的线程传入一个Routine(执行例程),该Routine只有一个参数类型为void的参数,以及返回类型为void的返回值。

而此时Routine作为类的成员函数,该函数的第一个参数是隐藏的this指针,因此这里的Routine函数,虽然看起来只有一个参数,而实际上它有两个参数,此时直接将该Routine函数作为创建线程时的执行例程是不行的,无法通过编译。

静态成员函数属于类,而不属于某个对象,也就是说静态成员函数是没有隐藏的this指针的,因此我们需要将Routine设置为静态方法,此时Routine函数才真正只有一个参数类型为void*的参数。

但是在静态成员函数内部无法调用非静态成员函数,而我们需要在Routine函数当中调用该类的某些非静态成员函数,比如Pop。因此我们需要在创建线程时,向Routine函数传入的当前对象的this指针,此时我们就能够通过该this指针在Routine函数内部调用非静态成员函数了。

任务类型的设计

我们将线程池进行了模板化,因此线程池当中存储的任务类型可以是任意的,但无论该任务是什么类型的,在该任务类当中都必须包含一个Run方法,当我们处理该类型的任务时只需调用该Run方法即可。

下面我们实现一个计算任务类:

#pragma once#include <iostream>//任务类
class Task
{
public:Task(int x = 0, int y = 0, char op = 0): _x(x), _y(y), _op(op){}~Task(){}//处理任务的方法void Run(){int result = 0;switch (_op){case '+':result = _x + _y;break;case '-':result = _x - _y;break;case '*':result = _x * _y;break;case '/':if (_y == 0){std::cerr << "Error: div zero!" << std::endl;return;}else{result = _x / _y;}break;case '%':if (_y == 0){std::cerr << "Error: mod zero!" << std::endl;return;}else{result = _x % _y;}break;default:std::cerr << "operation error!" << std::endl;return;}std::cout << "thread[" << pthread_self() << "]:" << _x << _op << _y << "=" << result << std::endl;}
private:int _x;int _y;char _op;
};

此时线程池内的线程不断从任务队列拿出任务进行处理,而它们并不需要关心这些任务是哪来的,它们只需要拿到任务后执行对应的Run方法即可。

主线程逻辑

主线程就负责不断向任务队列当中Push任务就行了,此后线程池当中的线程会从任务队列当中获取到这些任务并进行处理。

#include "Task.hpp"
#include "ThreadPool.hpp"int main()
{srand((unsigned int)time(nullptr));ThreadPool<Task>* tp = new ThreadPool<Task>; //线程池tp->ThreadPoolInit(); //初始化线程池当中的线程const char* op = "+-*/%";//不断往任务队列塞计算任务while (true){sleep(1);int x = rand() % 100;int y = rand() % 100;int index = rand() % 5;Task task(x, y, op[index]);tp->Push(task);}return 0;
}

在这里插入图片描述


相关文章:

【Linux】线程池

&#x1f387;Linux&#xff1a; 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让你看见坚持…...

运动版蓝牙耳机什么牌子的好、运动款蓝牙耳机推荐

何以解忧&#xff1f;唯有运动。事实已经无数次证明&#xff0c;运动不但可以让你更瘦身、更紧实&#xff0c;更重要的是精神状态也能焕然一新。不知道各位是不是也跟我一样&#xff0c;喜欢在运动的时候听着音乐。但是听音乐就需要有好的续航&#xff0c;否则运动一半没电了&a…...

MySQL中自带的数据库表相关介绍

mysql的自带数据库表主要有以下几个&#xff1a; &#xff08;1&#xff09;information_schema &#xff08;2&#xff09;performance_schema &#xff08;3&#xff09;mysql &#xff08;4&#xff09;sys &#xff08;5&#xff09;可能存在空数据库test 一、informa…...

【微信小程序】--注册小程序账号(一)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#…...

Java多线程 - 利用Callable或CompletableFuture实现多线程异步任务执行

文章目录1. Callable接口源码2. Future接口的源码3. RunnableFuture接口和FutureTask实现类4. 利用线程池和Callable接口实现异步执行任务5. 利用CompleteFutable实现多线程异步任务执行1. Callable接口源码 FunctionalInterface public interface Callable<V> {// 这个…...

【ts + webpack】贪吃蛇小游戏

目录 一、项目搭建 1.1 初始化项目 二、项目界面布局 三、完成Food类 四、完成记分牌类 五、初步完成snake类 六、创建游戏控制器类 - 键盘事件 七、GameControl - 使蛇移动 八、蛇撞墙和吃食检测 一、项目搭建 1.1 初始化项目 1.使用init命令生成package.json文件 …...

传统巨头生“变”,中国毫米波雷达市场战火再升级

进入2023年&#xff0c;中国车载毫米波雷达市场战火明显升级。 一方面&#xff0c;愈演愈烈的份额抢夺战不仅仅存在于几大传统巨头之间&#xff0c;也快速转移到与国产供应商之间&#xff1b;随着部分外资巨头的本土化战略深入落地&#xff0c;同时对国产供应商造成了压力。 …...

26岁曾月薪15K,现已失业3个月,我依然没有拿到offer......

我做测试5年&#xff0c;一线城市薪水拿到15K&#xff0c;中间还修了一个专升本&#xff0c;这个年限不说资深肯定也是配得上经验丰富的。今年行情不好人尽皆知&#xff0c;但我还是对我的薪水不是很满意&#xff0c;于是打算出去面试&#xff0c;希望可以搏一个高薪。 但真到面…...

华为OD机试 - 打印文件 | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...

【前端】浏览器的渲染流程(完整)

本文主要包含以下内容&#xff1a;浏览器渲染整体流程解析 HTML样式计算布局分层生成绘制指令分块光栅化绘制常见面试题浏览器渲染整体流程浏览器&#xff0c;作为用户浏览网页最基本的一个入口&#xff0c;我们似乎认为在地址栏输入 URL 后网页自动就出来了。殊不知在用户输入…...

华为OD机试 - 有效子字符串 | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...

抽象类和接口

抽象类和接口 抽象类和接口的定义 抽象类主要用来抽取子类的通用特性&#xff0c;作为子类的模板&#xff0c;它不能被实例化&#xff0c;只能被用作为子类的超类。 接口是抽象方法的集合&#xff0c;声明了一系列的方法操作&#xff0c;如果一个类实现了某个接口&#xff0c;…...

STM32DSP库汇总

前言 本文仅对stm32的DSP库进行汇总&#xff0c;具体函数使用方式持续更新…… 分类函数名描述 BasicMathFunctions 基础数学函数 abs绝对值add加法dot_prod向量点积mult乘法negate相反数offset 偏置 scale比例缩放shift移位sub减法 ComplexMathFunctions 复数数学函数 conj…...

C++类和对象----思想基础应用

类与对象的思想&基础应用一、类声明1.1、封装类的意义1.1.1、在设计类的时候&#xff0c;属性和行为写在一起&#xff0c;表现事物1.1.2、成员权限1.2、struct和class区别1.3、成员属性设置为私有二、对象的初始化和清理2.1、构造函数&析构函数2.2、构造函数分类方法一…...

​力扣解法汇总1792. 最大平均通过率

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 一所学校里有一些班级&#xff0c;每个班级里有一些学生&#xff0c;现在每个班…...

动手学深度学习(第二版)学习笔记 第二章

官网&#xff1a;http://zh.d2l.ai/ 视频可以去b站找 记录的是个人觉得不太熟的知识 第二章 预备知识 代码地址&#xff1a;d2l-zh/pytorch/chapter_preliminaries 2.1 数据操作 2.1. 数据操作 — 动手学深度学习 2.0.0 documentation 如果只想知道张量中元素的总数&#…...

CMake构建静态库与动态库以及使用

CMake构建静态库与动态库一、任务二、准备工作三、编译共享库四、ADD_LIBRARY指令五、编译静态库5.1、SET_TARGET_PROPERTIES指令5.2、GET_TARGET_PROPERTY指令六、动态库版本号七、安装共享库和头文件八、使用外部共享库和头文件8.1、准备工作8.2、引入头文件搜索路径8.3、为 …...

Linux 系统目录结构

登录系统后&#xff0c;在当前命令窗口下输入命令&#xff1a; ls / 你会看到如下图所示: 树状目录结构&#xff1a; 以下是对这些目录的解释&#xff1a; /bin&#xff1a; bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a; 这里…...

stable diffusion webui安装与使用(官方超简单教程)

预备依赖 下载miniconda 教程参考&#xff1a;https://blog.csdn.net/weixin_43828245/article/details/124768518安装git 参考教程&#xff1a;https://blog.csdn.net/weixin_46474921/article/details/127091723 下载sd-webui 官网 https://github.com/AUTOMATIC1111/stab…...

机器学习:学习k-近邻(KNN)模型建立、使用和评价

机器学习&#xff1a;学习k-近邻&#xff08;KNN&#xff09;模型建立、使用和评价 文章目录机器学习&#xff1a;学习k-近邻&#xff08;KNN&#xff09;模型建立、使用和评价一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.数据读取2.数据理解3.数据准备4.算…...

跨平台游戏引擎 Axmol-2.6.1 发布

Axmol 2.6.1 版本是一个以错误修复和功能改进为主的次要LTS长期支持版本 &#x1f64f;感谢所有贡献者及财务赞助者&#xff1a;scorewarrior、peterkharitonov、duong、thienphuoc、bingsoo、asnagni、paulocoutinhox、DelinWorks 错误修复 修复Android armv7架构崩溃问题&…...

Registry和docker有什么关系?

当遇到多个服务器需要同时传docker镜像的时候&#xff0c;一个一个的传效率会非常慢且压力完全在发送方的网络带宽&#xff1b;可以参考git hub&#xff0c;通常我们会用git push将代码传到git hub&#xff0c;如果谁需要代码用git pull就可以拉到自己的机器上&#xff0c;dock…...

Kafka存储机制核心优势剖析

文章目录 Kafka存储机制核心优势剖析1. **写入路径:Page Cache vs. 应用层缓存**2. **Page Cache工作原理解析**3. **顺序写盘 vs. 随机写盘**4. **资源利用最优化****为什么Page Cache方案更优?**1. **双缓存问题彻底解决**2. **读写路径统一优化**3. **故障恢复优势****生产…...

嵌入式开发之STM32学习笔记day20

STM32F103C8T6 PWR电源控制 1 PWR简介 PWR&#xff08;Power Control&#xff09;电源控制单元是STM32微控制器中一个重要的组成部分&#xff0c;它负责管理系统的电源管理功能&#xff0c;以优化功耗并提高效率。PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编…...

算法打卡12天

19.链表相交 &#xff08;力扣面试题 02.07. 链表相交&#xff09; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;** 题目数据…...

(11)Service Mesh架构下Java应用实现零信任安全模型

Service Mesh架构下Java应用实现零信任安全模型 📌 TL;DR: 本文详细介绍如何在Service Mesh架构中实现零信任安全模型,包括身份认证、授权控制、加密通信和持续监控四大核心技术,以及与Istio、Envoy等组件的集成方案。 目录 零信任安全模型概述关键技术实现最佳实践Service…...

为什么要选择VR看房?VR看房有什么优点?

VR看房&#xff1a;革新传统&#xff0c;重塑体验 在当今社会&#xff0c;虚拟现实&#xff08;VR&#xff09;技术正以前所未有的速度渗透到我们生活的各个领域&#xff0c;其中VR看房作为房地产领域的重要创新。本文将讨论为什么要选择VR看房以及VR看房的主要优点&#xff0…...

DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

记一个判决书查询API接口的开发文档

一、引言 在企业风控、背景调查、尽职调查等场景中&#xff0c;判决书查询是一个非常重要的环节。通过判决书查询&#xff0c;可以了解个人或企业的司法涉诉情况&#xff0c;为风险评估提供数据支持。本文将详细介绍如何开发和使用一个司法涉诉查询API接口&#xff0c;包括客户…...

使用深蓝词库软件导入自定义的词库到微软拼音输入法

我这有一个人员名单&#xff0c;把它看作一个词库&#xff0c;下面我演示一下如何把这个词库导入微软输入法 首先建一个text文件&#xff0c;一行写一个词条 下载深蓝词库 按照我这个配置&#xff0c;点击转换&#xff0c;然后在桌面微软输入法那右键&#xff0c;选择设置 点…...