Linux多线程——线程池

在这里插入图片描述

本章Gitee仓库:线程池、单例模式

文章目录

    • 1. 池化技术简述
    • 2. 线程池
    • 3. 单例模式
      • 3.1 单例模式特点
      • 3.2 饿汉方式和懒汉方式
      • 3.3 单例模式线程安全

1. 池化技术简述

C++中的STL,当空间不够时,会自动扩容,这个并不是我们需要多少,它就扩多少,之前自己实现的时候,选择的是1.5倍或者2倍扩容,这样的好处就是可以在一定空间范围内减少调整空间的次数,申请空间的底层也是系统调用,这样就能减少系统调用所花费的时间,本质就是空间换时间

2. 线程池

之前也写个简易的进程池,只不过没时间写笔记,看之后有没有时间写对应的笔记,有兴趣的可以先看看这个:进程池(进程通信——管道使用)

系统内部有一个(n个)任务队列,多个线程去竞争式去队列里面拿任务,使用线程的执行流不断向线程池push任务,然后线程池内部的线程来消化,这本质就是生产消费模型

image-20240125153124231

调用逻辑:

  1. 创建线程池
  2. 启动线程
  3. 主线程构建任务
  4. 线程处理任务(黑盒处理)
#pragma once#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<pthread.h>
#include<unistd.h>
#include"Task.hpp"static const int defaultNum = 5;    //默认5个struct threadInfo
{pthread_t tid;std::string name;
};template<class T>
class threadPool
{public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void WakeUp(){if(exitSingnal_)pthread_cond_broadcast(&cond_);elsepthread_cond_broadcast(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsEmpty(){return tasks_.empty();}std::string GetName(pthread_t tid){for(auto &e: threads_){if(e.tid == tid)    return e.name;}return "None";}public:static void *HandlerTask(void *args){threadPool<T> *tp = static_cast<threadPool<T> *>(args);std::string name =  tp->GetName(pthread_self());while(true){tp->Lock();while(tp->IsEmpty() && !tp->exitSingnal_){tp->ThreadSleep();}if(tp->exitSingnal_){//std::cout << " ?????" << std::endl;//sleep(1);tp->Unlock();break;}T t = tp->Pop();tp->Unlock();t();std::cout << "[thread " << name << "] is running," << " result:" << t.GetResult() << std::endl;usleep(1);//sleep(1); }}void Push(const T &in){Lock();tasks_.push(in);WakeUp();Unlock();}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Start(){for(int i = 0; i < threads_.size(); i++){threads_[i].name = std::to_string(i);pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);}}void Join(){exitSingnal_ = true;WakeUp();for(int i = 0; i < threads_.size(); i++){pthread_join(threads_[i].tid, nullptr);}}int GetSurplus(){return tasks_.size();}
public:threadPool(int num = defaultNum):threads_(num),exitSingnal_(false){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~threadPool(){std::cout << "~threadPool" << std::endl;pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);//sleep(3);}private:std::vector<threadInfo> threads_;    //线程池std::queue<T> tasks_;   //任务队列pthread_mutex_t mutex_;pthread_cond_t cond_;bool exitSingnal_;
};

HandlerTask

pthread_create()要求线程执行的函数返回值为void*,参数为void*

在类内,有一个this指针,设置成静态static的即可。

这里又会出现一个问题,静态成员无法直接访问类内成员,所以在传参的时候,直接传this指针过来

3. 单例模式

3.1 单例模式特点

对于一些类,只允许实例化一个对象,这就叫做单例。

3.2 饿汉方式和懒汉方式

我们日常生活当中,我们吃完饭直接洗碗,然后下顿饭吃的时候就直接拿碗筷吃,这就是饿汉方式;

如果我们吃完饭,不洗碗,等到下次吃饭的时候,再洗碗用这些碗吃饭,这就懒汉方式。

而懒汉方式的核心思想就是"延时加载",这能够优化启动的速度

以申请内存空间为例,我们向操作系统申请了一块内存空间,它只是允许我们访问,并不是直接加载到内存当中,而是在我们使用的时候,操作系统帮我们做缺页中断,然后再加载到内存,这本质上也是一种延时加载

延时加载整体上并没有提高效率,但是它在创建一个对象或者申请一块内存在申请和使用时间的配比发生了改变。

饿汉示例:

class Hungry
{
public:Hungry(){std::cout << "Hungry man" << std::endl;}
};Hungry h1;
Hungry h2;
Hungry h3;int main()
{sleep(3);std::cout << "main" << std::endl;return 0;
}

GIF 2024-1-28 10-14-34

饿汉就好比定义一个全局变量,全局变量在运行的时候就已经创建了,所以当全局变量较多的时候,势必会影响启动速度。

懒汉方式:

template <typename T>
class Singleton
{static T *inst;public:static T *GetInstance(){if (inst == NULL){inst = new T();}return inst;}
};

3.3 单例模式线程安全

image-20240128105402302

当多个线程判断这个是否为空的时候,判断完被切走,这就会导致对象被new成了多份,所以我们也需要对这个进行保护,既加锁。

全局或者静态初始化锁可以采用

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

image-20240128110410768

懒汉线程池:

#pragma once#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<pthread.h>
#include<unistd.h>
#include"Task.hpp"static const int defaultNum = 5;    //默认5个struct threadInfo
{pthread_t tid;std::string name;
};template<class T>
class threadPool
{public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void WakeUp(){if(exitSingnal_)pthread_cond_broadcast(&cond_);elsepthread_cond_broadcast(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsEmpty(){return tasks_.empty();}std::string GetName(pthread_t tid){for(auto &e: threads_){if(e.tid == tid)    return e.name;}return "None";}public:static void *HandlerTask(void *args){threadPool<T> *tp = static_cast<threadPool<T> *>(args);std::string name =  tp->GetName(pthread_self());while(true){tp->Lock();while(tp->IsEmpty() && !tp->exitSingnal_){tp->ThreadSleep();}if(tp->exitSingnal_){//std::cout << " ?????" << std::endl;//sleep(1);tp->Unlock();break;}T t = tp->Pop();tp->Unlock();t();std::cout << "[thread " << name << "] is running," << " result:" << t.GetResult() << std::endl;usleep(1);//sleep(1); }}void Push(const T &in){Lock();tasks_.push(in);WakeUp();Unlock();}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Start(){for(int i = 0; i < threads_.size(); i++){threads_[i].name = std::to_string(i);pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);}}void Join(){exitSingnal_ = true;WakeUp();for(int i = 0; i < threads_.size(); i++){pthread_join(threads_[i].tid, nullptr);}}int GetSurplus(){return tasks_.size();}//获取单例//静态方法,访问静态成员static threadPool<T> *GetInstance(){//2次判断//只有第一次创建对象会引发并发冲突问题,之后都是不符合的,所以之后并不需要判断,不用再做重复无效工作if(tp_ == nullptr)//相当于一个开关{pthread_mutex_lock(&lock_);if (tp_ == nullptr){tp_ = new threadPool<T>();}pthread_mutex_unlock(&lock_);}return tp_;   }//构造方法设置成私有
//凡是可能创建临时变量的,设置为私有
private:threadPool(int num = defaultNum):threads_(num),exitSingnal_(false){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~threadPool(){std::cout << "~threadPool" << std::endl;pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);//sleep(3);}threadPool(const threadPool<T>&)    = delete;const threadPool<T>& operator=(const threadPool<T>&)  =delete;private:std::vector<threadInfo> threads_;    //线程池std::queue<T> tasks_;   //任务队列pthread_mutex_t mutex_;pthread_cond_t cond_;bool exitSingnal_;static threadPool<T> *tp_;static pthread_mutex_t lock_;
};//
template<class T>
threadPool<T> *threadPool<T>::tp_ = nullptr;    //静态成员在类外初始化template<class T>
//全局或者静态采用PTHREAD_MUTEX_INITIALIZER
pthread_mutex_t threadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

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

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

相关文章

sqli-labs闯关

目录 1.安装靶场2.了解几个sql常用知识2.1联合查询union用法2.2MySQL中的通配符&#xff1a;2.3常用函数2.4数据分组 3.mysql中重要的数据库和表4.开始闯关4.1 Less-14.1.1 首先进行一次常规的注入4.1.2 深入解析 1.安装靶场 1.首先推荐使用github下载靶场源码 https://githu…

Matlab处理excel数据

我们新建个excel文档&#xff0c;用Matlab读取里面的内容&#xff0c;计算和判断里面的计算结果是否正确&#xff0c;并打印到另一个文档当中。 新建文档 新建输入文档&#xff0c;文件名TestExcel 编写脚本 [num,txt] xlsread(TestExcel.xlsx); SNcode num(:,1);%从序号中…

《微信小程序开发从入门到实战》学习九十六

7.2 基础内容组件 7.2.4 progress组件 progress组件的示例代码如下&#xff1a; <progress percent"20" show-info /> 7.3 表单组件 表单组件是用于收集信息的组件。第三章介绍了许多表单组件&#xff0c;包括form、input、textarea、picker、switch、butt…

eclipse启动Java服务及注意事项

1、导入项目 选择file——》import…——》Generate——》Exiting Projects into Workspace——》选择要导入的项目 2、添加tomcat 1&#xff09;点击Serves——》No servers are available. Click this link to create a new server… 2&#xff09;点击“Add…” 3&…

YOLO 全面回顾:从最初的YOLOv1到最新的YOLOv8、YOLO-NAS,以及整合了 Transformers 的 YOLO

YOLO 全面回顾 综述评估指标YOLO v1YOLO v2YOLO v3YOLO v4YOLOv5 与 Scaled-YOLOv4 YOLORYOLOXYOLOv6YOLOv7DAMO-YOLOYOLOv8PP-YOLO, PP-YOLOv2, and PP-YOLOEYOLO-NASYOLO with Transformers 综述 论文&#xff1a;https://arxiv.org/pdf/2304.00501.pdf 代码&#xff1a;gi…

MySQL知识点总结(一)——一条SQL的执行过程、索引底层数据结构、一级索引和二级索引、索引失效、索引覆盖、索引下推

MySQL知识点总结&#xff08;一&#xff09;——一条SQL的执行过程、索引底层数据结构、一级索引和二级索引、索引失效、索引覆盖、索引下推 一条SQL的执行过程索引底层数据结构为什么不使用二叉树&#xff1f;为什么不使用红黑树?为什么不使用hash表&#xff1f;为什么不使用…

Windows Qt C++ VTK 绘制三维曲线

Qt 自带数据可视化从文档上看&#xff0c;只能实现三维曲面。 QwtPlot3D在Qt6.6.0上没编译通过。 QCustomPlot 只能搞二维。 VTK~搞起。抄官网demo。 后续需求&#xff1a; 1、对数轴 2、Y轴逆序 3、Z轴值给色带&#xff0c;类似等高线图的色带 期待各位大佬多多指导。…

ad18学习笔记十六:v割

所谓“V割”是印刷电路板&#xff08;PCB&#xff09;厂商依据客户的图纸要求&#xff0c;事先在PCB的特定位置用转盘刀具切割好的一条条分割线&#xff0c;其目的是为了方便后续SMT电路板组装完成后的分板之用&#xff0c;因为其切割后的外型看起来就像个英文的“V”字型&…

C++从初级工程师到中级工程师【个人学习笔记】

目录 1 背景2 要点2.1 内存分区模型2.1.1 程序运行前2.1.2 代码 2.2.1 程序运行后栈区代码 1 背景 从这一章开始&#xff0c;开始学习C的面向对象编程&#xff0c;是C中的核心。 2 要点 2.1 内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&…

vue3项目+TypeScript前端项目—— vue3搭建项目+eslint+husky

今天来带大家从0开始搭建一个vue3版本的后台管理系统。一个项目要有统一的规范&#xff0c;需要使用eslintstylelintprettier来对我们的代码质量做检测和修复&#xff0c;需要使用husky来做commit拦截&#xff0c;需要使用commitlint来统一提交规范&#xff0c;需要使用preinst…

智能音箱喇叭杂音问题

智能音箱喇叭杂音问题 智能音箱生厂或出货过程会遇到多种喇叭播放有杂音的问题&#xff0e; 螺丝不匹配 智能音箱设备在生产过程&#xff0c;会有SPL测试喇叭失真&#xff0c;发现不良率8%的杂音问题&#xff0e; 分析原因是来料导入了新螺丝&#xff0c; 使用过程进入异物…

Python笔记15-实战小游戏飞机大战(中)

文章目录 创建第一个敌机创建一群敌机创建多行敌机让敌机移动射杀敌机生成新的敌机群结束游戏有敌机到达屏幕底端游戏结束 在上一篇基础上继续 本示例源码地址 点击下载 创建第一个敌机 在屏幕上放置外星人与放置飞船类似。每个外星人的行为都由Alien 类控制&#xff0c;我们…

docker 部署xxl-job

docker 部署xxl-job XXL-JOB github地址 https://github.com/xuxueli/xxl-job XXL-JOB 文档地址 https://www.xuxueli.com/xxl-job/ XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品…

利用ChatGPT提升工作效率的专业指南

利用ChatGPT提升工作效率的专业指南 一、引言 在数字化时代&#xff0c;人工智能助手已经成为提高工作效率的必备工具。其中&#xff0c;ChatGPT以其强大的自然语言处理能力&#xff0c;为我们提供了全新的工作方式。本文将深入探讨如何利用ChatGPT在各个工作领域中提升效率&a…

ChatGPT与文心一言:智能回复与语言准确性的较量

在当今数字化时代&#xff0c;随着人们对智能化技术的需求不断增长&#xff0c;智能回复工具也成为了日常生活中不可或缺的一部分。ChatGPT和文心一言作为两个备受瞩目的智能回复工具&#xff0c;在智能回复、语言准确性以及知识库丰富度等方面各有卓越之处。 本文将对这两者进…

LPC系列一个定时器不同频率

1.背景 最近研究的LPC804里只有一个ctimer&#xff0c;很多时候用的捉襟见肘的&#xff0c;官方给了一份双匹配的参考例程&#xff0c;不过实际用处不大。不过我花了一晚上的时间&#xff0c;终于研究出来将一个定时器拆成四个定时器用的办法了。这个方法适用于用回调函数的LP…

贪吃蛇游戏的实现

一.技术要点: 贪吃蛇需要掌握: c语言函数,枚举,结构体,动态内存管理,预处理指令,链表,Win32 API等 二.Win32 API 1.Win32 API简介 windows可以帮应用程序卡其视窗,描绘图案,使用周边设备,,Win32 API就是windows32位平台上的应用程序编程接口 2.控制台程序 (1).使用cmd命令…

Pycharm连接云算力远程服务器(AutoDL)训练深度学习模型全过程

前言&#xff1a;在上一篇windows搭建深度学习环境中&#xff0c;我试图使用笔记本联想小新air14的mx350显卡训练一个图像检测的深度学习模型&#xff0c;但是训练时长大概需要几天时间远超我的预期&#xff0c;所以我便选择租用GPU进行训练&#xff0c;在对多家平台对比后找到…

练习12.6_横向射击_Python编程:从入门到实践(第3版)

编写一个游戏&#xff0c;将一艘飞船放在屏幕左侧&#xff0c;并允许玩家上下移动飞船。在玩家按空格键时&#xff0c; 让飞船发射一颗在屏幕中向右飞行的子弹&#xff0c;并在子弹从屏幕中消失后将其删除。 ship_shooting.py import pygame import sys from leftship impor…

玩转WEB接口之三续篇【HTTPS证书申请 - nginx验证】

文章目录 一&#xff0c; 概述二&#xff0c;nginx下载三&#xff0c;访问域名1. 做域名映射2. 运行nginx并通过域名访问 四&#xff0c;配置SSL证书1. 配置证书文件2. nginx 添加证书文件 五、运行并验证1. 测试、重新加载2. https访问 一&#xff0c; 概述 接上篇 玩转WEB接…