Linux之线程池与单例模式

目录

线程池

线程池代码

单例模式

饿汉模式单例模式

懒汉模式单例模式


在前几期,我们已经学习了多线程的创建和控制,学习了多线程中的同步和互斥,学习了多线程中的条件变量和信号量,基于此我们实现了基于阻塞队列和基于环形队列的生产者和消费者模型。本期将在此基础上进一步拓展学习,学习线程池相关的内容。

线程池

在学习线程池之前,我们通过一个场景为大家引入。图示如下。

当我们用户在用户层使用malloc函数和new操作符进行内存空间的申请时,必须由操作系统在底层使用对应的系统调用接口进行内存的申请,具体步骤为,进程由用户态切换为内核态,然后在内核态通过对应的内存算法进行内存的申请。但不免有一种情况,用户频繁的申请大小为1MB的空间,操作系统在底层不断地使用内存算法申请小块空间,在这种情景下,频繁地使用内存置换算法申请小块空间的代价是非常大的,效率也非常的低。基于此我们事先会通过操作系统在底层通过内存算法申请一大块空间,这样用户在申请时,可以直接从操作系统事先申请好的空间中去申请,不用再让操作系统频繁地使用内存算法申请小块空间,大大提高了效率。所以,内存池也是类似的原理,最终为提高了代码的执行效率。 

内存池: 提前准备好的线程,用来随时处理任务,我们就称作线程池。

线程池代码

创建一个可以处理多个任务的线程池。

ThreadPool.hpp

#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>using namespace std;namespace threadpool
{const int g_num = 5;template <class T>class ThreadPool{public:ThreadPool(const int &num = g_num) : _num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}void Wait(){pthread_cond_wait(&_cond, &_mutex);}void Lock(){pthread_mutex_lock(&_mutex);}void Unlock(){pthread_mutex_unlock(&_mutex);}void Pop(T *out){*out = _task_queue.front();_task_queue.pop();}void Push(const T &data){Lock();_task_queue.push(data);Unlock();Wakeup();}void Wakeup(){pthread_cond_signal(&_cond);}static void *Rountine(void *args){// 线程分离,分线程退出时不用主线程去等待。pthread_detach(pthread_self());ThreadPool<T> *tp = (ThreadPool<T> *)args;while (true){tp->Lock();// 分线程去处理任务while (tp->_task_queue.empty()){tp->Wait();}T t;tp->Pop(&t);tp->Unlock();std::cout<<pthread_self()  << "得到的数据为 " << t << std::endl;}}void InitThreadPool(){pthread_t tid;for (int i = 0; i < g_num; i++){pthread_create(&tid, nullptr, Rountine, (void *)this);}}private:// 存放任务的队列queue<T> _task_queue;// 表示线程池中线程的数目int _num;pthread_mutex_t _mutex;pthread_cond_t _cond;};}

test.cc

#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;int main()
{ThreadPool<int> tp;tp.InitThreadPool();// 随机数种子srand((long long)time(nullptr));while (true){int a=rand()%20;tp.Push(a);cout << "发送的数据为" << a << endl;sleep(1);}return 0;
}

运行结果如下。

由运行结果可知,运行结果符合预期。 

单例模式

在学习单例模式之前,我们了解一下什么是设计模式,模式其实就是特定的场景给予特定的解决方案。在人类社会中,成熟的行业都会有成熟的设计模式。何为单例模式,单例模式其实就是一个类只允许实例化出一个对象的设计模式。

饿汉模式单例模式

饿汉就是,工资日结。

懒汉模式单例模式代码。

template <class T>
class SigDistance
{
private:static SigDistance<T> _t;public:static SigDistance<T> *GetDistance(){return &_t;}
};

懒汉模式单例模式

 懒汉就是,工资月结。

template <class T>
class SigDistance
{
private:static SigDistance<T> *_t;
public:static SigDistance<T> *GetDistance(){if (_t == nullptr){_t=new SigDistance();}return _t;}
};SigDistance<T>* SigDistance<T>::_t = nullptr;

 基于懒汉单例模式的线程池

线程池往往只有一个,所以我们把线程池类设计成了单例模式,代码如下。

Thread.hpp

#pragma once
#include <queue>
#include <pthread.h>
#include <iostream>using namespace std;namespace threadpool
{const int g_num = 5;template <class T>class ThreadPool{private:ThreadPool<T>(const int &num = g_num) : _num(num){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~ThreadPool<T>(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}ThreadPool<T>(const ThreadPool<T> &tp) = delete;ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;void Wait(){pthread_cond_wait(&_cond, &_mutex);}void Lock(){pthread_mutex_lock(&_mutex);}void Unlock(){pthread_mutex_unlock(&_mutex);}public:void Pop(T *out){*out = _task_queue.front();_task_queue.pop();}void Push(const T &data){Lock();_task_queue.push(data);Unlock();Wakeup();}void Wakeup(){pthread_cond_signal(&_cond);}static ThreadPool<T> *GetDistance(){static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;if(_tp==nullptr){pthread_mutex_lock(&lock);if (_tp == nullptr){_tp = new ThreadPool<T>();}}_tp->InitThreadPool();pthread_mutex_unlock(&lock);return _tp;}static void *Rountine(void *args){// 线程分离,分线程退出时不用主线程去等待。pthread_detach(pthread_self());ThreadPool<T> *tp = (ThreadPool<T> *)args;while (true){tp->Lock();// 分线程去处理任务while (tp->_task_queue.empty()){tp->Wait();}T t;tp->Pop(&t);tp->Unlock();std::cout << pthread_self() << "得到的数据为 " << t << std::endl;}}void InitThreadPool(){pthread_t tid;for (int i = 0; i < g_num; i++){pthread_create(&tid, nullptr, Rountine, (void *)this);}}private:// 存放任务的队列queue<T> _task_queue;// 表示线程池中线程的数目int _num;static ThreadPool<T> *_tp;pthread_mutex_t _mutex;pthread_cond_t _cond;};template <class T>ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
}

需要注意的是,静态成员变量需要再类外进行初始化。 

test.cc

#include "ThreadPool.hpp"
#include <iostream>
#include <unistd.h>
#include <time.h>
using namespace std;
using namespace threadpool;int main()
{ThreadPool<int> *tp = ThreadPool<int>::GetDistance();// 随机数种子srand((long long)time(nullptr));while (true){int a = rand() % 20;tp->Push(a);cout << "发送的数据为" << a << endl;sleep(1);}return 0;
}

运行结果如下。

运行结果符合预期。

以上便是线程池以及单例模式的所有内容。

本期内容到此结束^_^ 

 

 

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

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

相关文章

青蛙云的云服务器有哪些显著优势?

青蛙云的云服务器具有以下显著优势&#xff0c;这些特点使得它成为企业构建高效IT基础设施的重要选择&#xff1a; 1.高性能硬件 青蛙云服务器采用高性能的服务器硬件进行部署&#xff0c;确保服务的稳定性和高效运行&#xff0c;为用户提供卓越的计算能力。 2. 弹性资源 支持资…

赛车微型配件订销管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 赛车微型配件行业通常具有产品多样性、需求不确定性、市场竞争激烈等特点。配件供应商需要根据市场需求及时调整产品结构和库存&#xff0c;同时要把握好供应链管理和销售渠道。传统的赛车微型配件订销管理往往依赖于人工经验和简单的数据分析&#xff0c;效率低下且容易…

原生js解析token信息

原生js解析token信息&#xff1a; 代码&#xff1a; const tokenString localStorage.getItem(Token) const strings tokenString.split(.) //通过split()方法将token转为字符串数组 //取strings[1]数组中的第二个字符进行解析 const userinfo JSON.parse(decodeURICompon…

KGA:AGeneral Machine Unlearning Framework Based on Knowledge Gap Alignment

文章目录 摘要1 引言2 相关工作3 符号与定义4 我们的 KGA 框架4.1 KGA框架知识差距对齐目标 4.2 KGA在自然语言处理任务中的应用文本分类机器翻译响应生成 5 实验设置数据集评估指标参数设置比较方法 6 实验结果6.1 主要比较结果6.2 KGA 的优越性分析降低语言模型概率比较 6.3 …

swiftUI桥接UIKit

swiftUI桥接UIKit struct TestView: UIViewRepresentable {Binding var text: String // 该文本在swiftUI中可以修改let text: String // 不可修改func makeUIView(context: Context) -> UIView {let view UIView()// 例子asd.frame CGRect(x: 0, y: 0, width: 300, heig…

解决安装dlib失败

安装dlib时失败&#xff0c;报错如下&#xff1a; $pip install dlib Defaulting to user installation because normal site-packages is not writeable Looking in indexes: https://mirrors.huaweicloud.com/repository/pypi/simple Collecting dlibDownloading https://mi…

《上古重生》V20241127111039官方中文学习版

《上古重生》官方中文版https://pan.xunlei.com/s/VODab-jcgXUAgJbj2b1-11qUA1?pwdc7di# 一款考验玩家技巧的砍杀游戏&#xff0c;从玩家到敌人&#xff0c;通通身穿古代的厚重盔甲&#xff0c;进行“重量级”的近身搏斗。在充满Cult元素的第一人称视角大冒险中杀出一条血路吧…

什么是负载均衡?NGINX是如何实现负载均衡的?

大家好&#xff0c;我是锋哥。今天分享关于【什么是负载均衡&#xff1f;NGINX是如何实现负载均衡的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 什么是负载均衡&#xff1f;NGINX是如何实现负载均衡的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源…

数组排序------冒泡排序

要求&#xff1a;给定一个数组&#xff0c;让数组升序&#xff08;降序&#xff09;排序 思路&#xff1a; 假设升序排序&#xff1a; ①&#xff1a;将数组中相邻元素从前往后依次进行比较&#xff0c;如果前一个元素比后一个元素大&#xf…

Qt 坐标系统和坐标变换

一、概述:1、QPainter在QPaintDevice上绘图的默认坐标系统是&#xff0c;原点(0,0)在左上角&#xff0c;x轴正方向水平向右&#xff0c;y轴正方向竖直向下的坐标系。 2、为了绘图的方便&#xff0c;QPainter提供了一些坐标变换的功能&#xff0c;通过平移、旋转、缩放等坐标变…

SpringBoot + 九天大模型(文生图接口)

目录 1、先到九天大模型的官网&#xff08;LLM Studio&#xff09;上订阅模型的推理服务&#xff0c;得到APIKey&#xff0c;后期需要使用它生成token才能调用模型的推理服务。 2、在SpringBoot项目里面的pom.xml文件中添加九天大模型的相关依赖&#xff0c;后面会使用到其中…

1. npm 常用命令详解

npm 常用命令详解 npm&#xff08;Node Package Manager&#xff09;是 Node.js 的包管理工具&#xff0c;用于安装和管理 Node.js 应用中的依赖库。下面是 npm 的一些常用命令及其详细解释和示例代码。 镜像源 # 查询当前使用的镜像源 npm get registry# 设置为淘宝镜像源 …

12. C语言 数组与指针(深入理解)

本章目录: 前言1. 什么是数组&#xff1f;2. 数组的声明与初始化声明数组初始化数组 3. 访问数组元素遍历数组 4. 获取数组长度使用 sizeof 获取长度使用宏定义简化 5. 数组与指针数组名与指针的区别使用指针操作数组 6. 多维数组遍历多维数组 7. 数组作为函数参数8. 高级技巧与…

Leetcode 120. 三角形最小路径和 动态规划

原题链接&#xff1a;Leetcode 120. 三角形最小路径和 class Solution { public:int minimumTotal(vector<vector<int>>& triangle) {int n triangle.size();if (n 1)return triangle[0][0];int dp[n][n];dp[0][0] triangle[0][0];int res INT_MAX;for (in…

网络安全概论

网络安全概论--网络基础知识--防火墙技术--身份识别技术--虚拟专用网络--入侵检测技术--病毒和恶意代码 --业务连续性计划--安全管理--信息系统安全方案设计方法 一、网络安全面临的威胁 物理安全威胁、操作系统的安全缺陷、网络协议的安全缺陷、应用软件的实现缺陷、用户使…

设计模式 行为型 状态模式(State Pattern)与 常见技术框架应用 解析

状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许对象在内部状态改变时改变其行为&#xff0c;使得对象看起来好像修改了它的类。这种设计模式的核心思想是将对象的状态和行为封装成不同的状态类&#xff0c;通过状态对象的行为改变来避免…

Java 线程池 ThreadPoolExecutor 底层原理与源码分析

引言 我们探讨了 ThreadPoolExecutor 的基本概念、内部机制以及部分源码实现。本文将继续深入研究该类的更多细节&#xff0c;并结合提供的文档内容&#xff0c;进一步解析线程池的工作流程、任务提交和执行的具体过程&#xff0c;以及如何通过自定义配置来优化性能。 一、线…

Mysql--基础篇--视图,存储过程,触发器

1、视图 MySQL视图&#xff08;View&#xff09;是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。但是&#xff0c;视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表&#…

某团 mtgsig1.2 | sdkVersion: 3.0.0 签名算法分析记录(2025/1/9)

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#…

(二)最长公共子序列、最长上升子序列、最大子段和、三角形最小路径和、矩阵连乘、0-1背包

最近刚考完算法设计分析课的考试&#xff0c;复习总结一下期末考试的几道算法题吧 目录 LCR 095. 最长公共子序列 300. 最长递增子序列 53. 最大子数组和 LCR 100. 三角形最小路径和 矩阵连乘问题 0-1背包 LCR 095. 最长公共子序列 给定两个字符串 text1 和 text2&#xff…