【Linux】线程池和线程补充内容

article/2025/8/13 11:53:09

在这里插入图片描述

个人主页~


线程池

  • 一、线程池简介
    • 单例模式线程池简介
  • 二、单例模式线程池的实现
    • 1、ThreadPool.hpp
    • 2、Task.hpp
    • 3、main.cpp
  • 三、其他常见锁
    • 读写锁

一、线程池简介

池化技术我们并不陌生,我们在前面的文章中实现过进程池,这里线程池的作用也是先申请资源交给用户区,然后用户在使用的时候就不用再去内核申请了,直接去池中申请,效率提高,是一种以空间换时间的方法

单例模式线程池简介

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例,核心思想是限制一个类只能创建一个对象,并提供一个统一的方法让其他代码可以访问这个唯一的对象,这样可以避免在系统中创建多个功能相同的对象,从而节省系统资源,保证数据的一致性和操作的一致性

单例的实现有两种方式,被称为饿汉方式和懒汉方式,饿汉方式的核心思想是在类加载时就创建单例实例,无论后续是否会使用该实例,这种方式利用了静态成员变量的特性,在程序启动时,类的静态成员变量会被自动初始化,从而保证实例的唯一性,懒汉方式的核心思想是在第一次使用单例实例时才进行创建,即 “延迟加载”,这种方式避免了在程序启动时就创建实例,从而减少了不必要的资源消耗

二、单例模式线程池的实现

1、ThreadPool.hpp

#pragma once#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>struct ThreadInfo
{pthread_t tid;std::string name;
};static const int defalutnum = 5;template <class T>
class ThreadPool
{
public:void Lock(){pthread_mutex_lock(&mutex_);}void Unlock(){pthread_mutex_unlock(&mutex_);}void Wakeup(){pthread_cond_signal(&cond_);}void ThreadSleep(){pthread_cond_wait(&cond_, &mutex_);}bool IsQueueEmpty(){return tasks_.empty();}std::string GetThreadName(pthread_t tid){for (const auto &ti : threads_){if (ti.tid == tid)return ti.name;}return "None";}public:static void *HandlerTask(void *args){ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);std::string name = tp->GetThreadName(pthread_self());while (true){tp->Lock();while (tp->IsQueueEmpty()){tp->ThreadSleep();}T t = tp->Pop();tp->Unlock();t();std::cout << name << " run, "<< "result: " << t.GetResult() << std::endl;}}void Start(){int num = threads_.size();for (int i = 0; i < num; i++){threads_[i].name = "thread-" + std::to_string(i + 1);pthread_create(&(threads_[i].tid), nullptr,HandlerTask, this);}}T Pop(){T t = tasks_.front();tasks_.pop();return t;}void Push(const T &t){Lock();tasks_.push(t);Wakeup();//唤醒线程Unlock();}//实现单例模式,确保线程池只有一个实例static ThreadPool<T> *GetInstance(){//这里套两层if判断是为了避免多个线程同时通过第一次检查而创建多个实例//只有在第一次进入的时候tp_有可能等于nullptr,之后就不可能会了,在外面再加一层//可以判断完直接跳过括号中的代码,不去争夺锁if (nullptr == tp_){pthread_mutex_lock(&lock_);if (nullptr == tp_){std::cout << "log: singleton create done first!" << std::endl;tp_ = new ThreadPool<T>();}pthread_mutex_unlock(&lock_);}return tp_;}private://单例模式要把构造函数私有化,不被类外访问到ThreadPool(int num = defalutnum) : threads_(num){pthread_mutex_init(&mutex_, nullptr);pthread_cond_init(&cond_, nullptr);}~ThreadPool(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&cond_);}//删除拷贝构造函数,防止线程池对象被拷贝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_;//用于线程同步的条件变量static ThreadPool<T> *tp_;//静态指针,用于实现单例模式static pthread_mutex_t lock_;//静态互斥锁,用于在创建单例时进行线程同步
};//静态成员变量初始化
template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

2、Task.hpp

#pragma once
#include <iostream>
#include <string>std::string opers="+-*/%";enum{DivZero=1,ModZero,Unknown
};class Task
{
public:Task(){}Task(int x, int y, char op) : data1_(x), data2_(y), oper_(op), result_(0), exitcode_(0){}void run(){switch (oper_){case '+':result_ = data1_ + data2_;break;case '-':result_ = data1_ - data2_;break;case '*':result_ = data1_ * data2_;break;case '/':{if(data2_ == 0) exitcode_ = DivZero;else result_ = data1_ / data2_;}break;case '%':{if(data2_ == 0) exitcode_ = ModZero;else result_ = data1_ % data2_;}            break;default:exitcode_ = Unknown;break;}}void operator ()(){run();}std::string GetResult(){std::string r = std::to_string(data1_);r += oper_;r += std::to_string(data2_);r += "=";r += std::to_string(result_);r += "[code: ";r += std::to_string(exitcode_);r += "]";return r;}std::string GetTask(){std::string r = std::to_string(data1_);r += oper_;r += std::to_string(data2_);r += "=?";return r;}~Task(){}private:int data1_;int data2_;char oper_;int result_;int exitcode_;
};

3、main.cpp

#include <iostream>
#include <ctime>
#include "ThreadPool.hpp"
#include "Task.hpp"int main()
{std::cout << "process running..." << std::endl;ThreadPool<Task>::GetInstance()->Start();srand(time(nullptr));while(true){//构建任务int x = rand() % 10 + 1;usleep(10);int y = rand() % 5;char op = opers[rand()%opers.size()];Task t(x, y, op);ThreadPool<Task>::GetInstance()->Push(t);//交给线程池处理std::cout << "main thread make task: " << t.GetTask() << std::endl;sleep(1);}
}

在这里插入图片描述

三、其他常见锁

  • 悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁,当其它线程想要访问数据时,被阻塞挂起,互斥锁就是悲观锁

  • 乐观锁: 每次取数据的时候,总是乐观的认为数据不会被其他线程修改,因此不上锁,但是在更新数据前,会判断其他线程在更新前有没有对数据进行修改,主要采用两种方式:版本号机制和 CAS 操作

  • CAS 操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等,如果相等则用新值更新,若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试

  • 自旋锁:当一个进程申请锁失败时,不是将自己挂起,而是继续去申请锁,使用这种锁的前提是,线程在临界区中执行的时间要足够的短

读写锁

读写锁是一种同步机制,用于在多线程环境中对共享资源进行并发访问控制,它允许多个线程同时进行读操作,但在进行写操作时会独占资源,以保证数据的一致性和完整性

  • 基本概念:读写锁将对共享资源的访问分为读操作和写操作两种类型,多个线程可以同时获取读锁,并行地进行读操作,因为读操作不会修改共享资源,不会产生数据竞争问题,而写操作是独占的,当一个线程获取写锁时,其他线程无论是读操作还是写操作都必须等待,直到写锁被释放

  • 读写锁的三种状态

    • 无锁状态:此时没有线程持有读锁或写锁,任何线程都可以尝试获取读锁或写锁
    • 读锁状态:有一个或多个线程持有读锁,此时可以有其他线程继续获取读锁,但不能有线程获取写锁
    • 写锁状态:有一个线程持有写锁,此时其他线程不能获取读锁或写锁,直到写锁被释放
  • 优点

    • 并发性能高:允许多个线程同时进行读操作,提高了对共享资源的并发访问能力,特别适用于读多写少的场景
    • 数据一致性:写操作是独占的,保证了在写操作期间不会有其他线程同时访问共享资源,从而确保了数据的一致性
  • 缺点

    • 实现复杂:读写锁的实现比普通的互斥锁更复杂,需要处理读锁和写锁的竞争关系
    • 写饥饿问题:在高并发的读操作场景下,可能会出现写线程长时间无法获取写锁的情况,即写饥饿问题
  • 使用场景

    • 适用于读操作频繁、写操作较少的场景,例如:
    • 缓存系统:缓存系统通常需要频繁读取数据,而更新数据的操作相对较少,使用读写锁可以让多个线程同时读取缓存,提高缓存的访问性能
    • 配置文件管理:配置文件在程序运行过程中通常只需要读取,而修改配置文件的操作比较少,使用读写锁可以让多个线程同时读取配置文件,而在修改配置文件时进行独占访问

今日分享就到这了~

在这里插入图片描述


http://www.hkcw.cn/article/lcddPnTQDa.shtml

相关文章

Linux:进程间通信---消息队列信号量

文章目录 1.消息队列1.1 消息队列的原理1.2 消息队列的系统接口 2. 信号量2.1 信号量的系统调用接口 3. 浅谈进程间通信3.1 IPC在内核中数据结构设计3.2 共享内存的缺点3.3 理解信号量 序&#xff1a;在上一章中&#xff0c;我们引出了命名管道和共享内存的概念&#xff0c;了解…

【HarmonyOS Next之旅】DevEco Studio使用指南(五) -> 添加/删除Module

目录 1 -> 创建新的Module 2 -> 导入Module 3 -> 配置distroFilter/distributionFilter分发规则 4 -> 删除Module 1 -> 创建新的Module Module是应用/元服务的基本功能单元&#xff0c;包含了源代码、资源文件、第三方库及应用/元服务配置文件&#xff0c;…

Linux离线部署Dify:Docker从镜像拉取打包到无网环境中部署

文章目录 前言一、在线环境操作1. 获取dify项目&#xff08;使用魔法&#xff09;2.进入项目中docker目录3.镜像拉取4.查看镜像5.镜像打包6.镜像&#xff08;项目&#xff09;上传 二、离线环境操作1.镜像导入2.启动服务3.验证容器启动状态4.访问服务 三、部分参考链接 前言 设…

34年聘用职工被强制“自愿转保” 退休手续拖延逾一年

冯爱文,一位年满61岁的河北石家庄市井陉县税务局原聘用人员,已经一年多没有办理退休手续,没有任何收入来源,全靠子女接济和回收旧衣服为生。他在办理退休手续时被县社保局要求签署“自愿”转为企业或灵活就业人员参保申请书,因拒绝签字,退休手续被拖延超过一年。在石家庄…

英国首相批法拉奇“画饼” 经济方案异想天开

英国首相基尔斯塔默于5月29日批评极右翼政党英国改革党党首奈杰尔法拉奇提出的经济方案是“异想天开”,并警告如果该政党上台执政,英国经济将遭受重创。近期英格兰部分地区举行的地方选举中,英国改革党取得显著进展,赢得超过670个地方议会席位,并在两场市长选举和一场议会…

澳媒:嘉能可将300亿澳元资产转至澳 为合并铺路

澳大利亚金融评论报网站报道,全球大宗商品巨头嘉能可通过大规模重组将超过300亿澳元的海外资产转移到一家澳大利亚子公司,此举旨在为未来与其他大宗商品巨头达成大型合并做准备。这些资产包括嘉能可在加拿大、南非和哥伦比亚的煤矿业务,在阿根廷的铜资源业务以及在南非的锰、…

成都一男子伤人后自伤颈部 警方通报 因感情纠纷引发

2025年5月30日15时许,中纱帽街8号负一层发生一起持刀伤人事件。接警后,公安机关迅速组织警力到场处置,并当场控制了犯罪嫌疑人陆某某(男,26岁)。经初步调查,陆某某因感情纠纷前往前女友胡某某(女,24岁)的工作单位,双方发生口角后,陆某某持随身携带的水果刀将胡某某…

航电系统音频模块设计要点与技术突破

一、设计要点 音频输出模块&#xff1a; 1. 高可靠性 符合航空级环境标准&#xff08;DO-160G&#xff09;&#xff0c;耐受温度、振动、湿度极端变化。 冗余设计&#xff1a;双通道输出&#xff0c;支持自动切换故障通道。 2. 抗干扰设计 电磁兼容性&#xff08;EMC&a…

优化俄罗斯方块小游戏

前言 在之前的俄罗斯方块的小游戏中进行了修改&#xff0c;但是一定还存在着一些问题&#xff0c;欢迎大家在评论区留言。 目前是进行了以下的一些优化&#xff1a; 普通方块颜色除了选用马卡龙配色还增加了一些其他好看的颜色&#xff0c;对于特殊方块的颜色使用红橙黄绿蓝…

智能物资出入库管控系统

概述 智能物资管理系统利用RFID自动识别技术&#xff0c;物联网技术、人脸识别、指纹、指静脉生物识别技术&#xff0c;应用于军械装备的管理&#xff0c;可实时准确采集军械装备编配、 储存、供应、使用等数据&#xff0c;实时掌握军械装备物资的分布及数量 状况。细化管理到…

朱雀玄武敕令三战高考 改名事件成考题

前不久,“00后”小伙“朱雀玄武敕令”申请改名为“周天紫微大帝”的新闻引起了广泛关注。他近期正准备参加今年高考,并在网上搜寻到的模拟考试卷中看到了关于自己改名一事的考题。据了解,朱雀玄武敕令出生于2001年,父母为他起名“朱云飞”。2025年1月,他改名为“朱雀玄武敕…

北京7000余社区村配儿童主任 关爱困境儿童

5月29日上午,六一国际儿童节来临之际,丰台区青塔街道蔚园社区儿童主任韩玉兰为辖区两户困境儿童家庭送来了粮、油、饮水杯、雨伞等慰问品。北京市7000多个社区(村)每个社区(村)至少配置了1名儿童主任,他们通过入户探访、协助申请保障、解释福利政策等方式,为困境儿童家…

涨薪技术|0到1学会性能测试第90课-性能测试构建

至此关于系统资源监控、apache监控调优、Tomcat监控调优、JVM调优、Mysql调优、前端监控调优、接口性能监控调优的知识已分享完,今天开始学习性能测试流程知识。后续文章都会系统分享干货,带大家从0到1学会性能测试。 性能测试设计完成后,接下来需要将设计的策略变成现实,…

李嫣高中毕业 长发披肩神似王菲 颜值抢镜

近日,王菲与李亚鹏的女儿李嫣在2025年5月底从伦敦的高中毕业。她穿着毕业服与同学们合影,长发披肩,颜值出众。网友们纷纷表示,李嫣神似母亲王菲,在人群中格外引人注目。此前,李嫣经历了四次唇腭裂修复手术,面部状态已接近自然。责任编辑:zhangxiaohua

技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型

融智学工程技术体系&#xff1a;五维协同架构 基于邹晓辉教授的框架&#xff0c;工程技术体系重构为&#xff1a;技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型&#xff1a; math \mathbb{E}_{\text{技}} \underbrace{\prod_{\text{Dis}} \text{TechnoCore}}_{\…

中国驻美大使:大院铁幕只会自我孤立 封锁难阻科技创新

2025年5月28日,中国驻美国大使馆举办“我的中国相册——我的中国足迹”影片首映会暨现代化的中国体验活动。谢锋大使和夫人王丹、邱文星公使以及美国各界人士共200余人出席了此次活动。谢锋在致辞中表示,中国走出了一条致力于团结奋斗、共同富裕、全面发展、持续发展与和平发…

清华大学发布李兆杰教授讣告 沉痛悼念著名国际法学者

5月29日晚,清华大学法学院发布讣告,悼念李兆杰教授。李兆杰教授于2025年5月29日在北京因病逝世,享年70岁。李兆杰教授是汉族,籍贯山东省东明县,1955年出生于吉林省长春市。他曾在北京大学国际法研究所和清华大学法学院任教,是改革开放以来中国新一代国际法学者中的领军人…

端午游屈原故里探访三峡秘境 寻味民俗之旅

每年端午节,人们忙着吃粽子、赛龙舟,但屈原故里秭归却藏着许多不为人知的传说。今天,让我们一起踏上这条神秘的文旅路线,探索那些课本里没有的故事,感受屈原文化的独特魅力。文旅路线从屈原故里纪念馆开始。这里不仅展示了屈原的生平事迹,还有许多珍贵文物。走进馆内,仿…

15.5 【TS基础项目】构建随机密码生成器

在现代 Web 应用中&#xff0c;生成强大而安全的密码对于保护用户账户免受未经授权访问至关重要。使用 TypeScript 构建一个随机密码生成器&#xff0c;可以通过混合字母、数字和特殊字符来创建不可预测、复杂的密码&#xff0c;从而显著提升安全性。 我们要构建什么&#xff…

上海一公交站椅子矮出新高度 乘客叫苦不迭

上海街头的许多公交车站都设有候车座椅,这些座椅成为老人们等车时的好帮手。然而,并不是每个公交站点都能让乘客感到舒心。家住共青森林公园附近的市民反映,该公园正门的公交102路、124路和147路站点的座椅高度异常低矮,甚至比幼儿园的板凳还要矮,导致乘客坐着不舒服,蹲下…