Linux--线程安全的单例模式--自旋锁--0211
1. 线程安全的单例模式
1.1 什么是单例模式
某些类, 只应该具有一个对象(实例), 就称之为单例.
1.1.1 懒汉方式实现单例模式
以上篇博文的线程池为例
Liunx--线程池的实现--0208 09_Gosolo!的博客-CSDN博客
- 实现懒汉模式首先要先将构造函数私有化,并禁止生成默认的拷贝构造函数,赋值运算符重载,不能随意的构造出来对象。
- 其次增加一个静态的线程池对象,才符合单例的条件。
- 然后需要有一个函数可以用来构造对象,由于该函数需要知道静态线程池对象是否不为空,也就是需要访问静态成员,所以该函数也必须是静态的
template<class T>
class ThreadPool
{//...
private:ThreadPool(int thread_num=g_thread_num):num_(thread_num){//创造线程的空间 构造线程for(int i=1;i<=num_;i++){//每个线程的编号 回调函数 输出型参数threads_.push_back(new Thread(i,routine,this)); }pthread_mutex_init(&lock,nullptr);pthread_cond_init(&cond,nullptr);}ThreadPool(const ThreadPool<T>& other)=delete;const ThreadPool<T> operator=(const ThreadPool<T>& other)=delete;//...
public:static ThreadPool<T>* getThreadPool(int num=g_thread_num){if(nullptr==thread_ptr){thread_ptr=new ThreadPool<T>(num);}return thread_ptr;}
private:std::vector<Thread*> threads_;int num_;std::queue<T> task_queue_;pthread_mutex_t lock;//保护临界区(任务队列)的一把锁pthread_cond_t cond;static ThreadPool<T>* thread_ptr;//静态成员 在类外初始化
};
template<class T>
ThreadPool<T>* ThreadPool<T>::thread_ptr =nullptr;
问题:
由于我们这个项目是线程池,有没有可能多个线程同时访问getThreadPool函数,都进入到了thread_ptr与nullptr这一步判断?
会的,这里是线程不安全的,我们需要加锁以保证安全。
1.1.2 懒汉方式实现线程安全的单例模式
在静态成员函数中加锁,所以该锁也需要是静态的成员变量。
template<class T>
class ThreadPool
{//...
private:ThreadPool(){}
public:static ThreadPool<T>* getThreadPool(int num=g_thread_num){if(nullptr==thread_ptr){//lockGuard lockguard(&mutex); 锁的封装 详细见上篇博文pthread_mutex_lock(&mutex);if(nullptr==thread_ptr){thread_ptr=new ThreadPool<T>(num);}pthread_mutex_unlock(&mutex);}return thread_ptr;}
private:std::vector<Thread*> threads_;int num_;std::queue<T> task_queue_;pthread_mutex_t lock;//保护临界区(任务队列)的一把锁pthread_cond_t cond;static ThreadPool<T>* thread_ptr;//静态成员 在类外初始化static pthread_mutex_t mutex ;//静态成员 在类外初始化
};
template<class T>
ThreadPool<T>* ThreadPool<T>::thread_ptr =nullptr;
template<class T>
pthread_mutex_t ThredPool<T>::mutex=PTHREAD_MUTEX_INITIALIZER;//静态的锁不需要手动释放
问题:
为什么要判断两次呢?
其他线程想要调用该函数时,如果没有最外层的判断就一定会进行申请锁、释放锁的操作。这样写可以有效减少未来必定要加锁检测的问题
2.其他常见的各种锁
- 悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
- 乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
- CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。
- 自旋锁,公平锁,非公平锁?
我们之前学的锁都是悲观锁。
自旋锁:本质就是通过不断的检测状态(一直打电话催促),来进行资源是否就绪的方案。
(互斥锁:只检测一次,临界资源没就绪就直接挂起。)
什么时候使用自旋锁?临界资源就绪的时间短时(是一个相对的概念,取决于场景的容忍度)。
自旋锁的使用
#include <pthread.h>
int pthread_spin_init(pthread_spinlock_t* lock,int pshared);
int pthread_spin_destroy(pthread_spinlock_t* lock);
无论是挂起等待还是自旋本身都是pthread库帮我们做的,我们只需要使用接口。
#include <pthread.h>
int pthread_spin_lock(pthread_spinlock_t* lock);
int pthread_spin_trylock(pthread_spinlock_t* lock); //自旋一次 不成功就返回
3.读者写者 与消费者生产者的区别
读写锁
公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。
写独占,读共享,读锁优先级高。
区别:
消费者会取走数据,所以消费者消费者之间是互斥关系。二读者写者是共享关系。
相关文章:
Linux--线程安全的单例模式--自旋锁--0211
1. 线程安全的单例模式 1.1 什么是单例模式 某些类, 只应该具有一个对象(实例), 就称之为单例. 1.1.1 懒汉方式实现单例模式 以上篇博文的线程池为例 Liunx--线程池的实现--0208 09_Gosolo!的博客-CSDN博客 实现懒汉模式首先要先将构造函数私有化,…...

图文解说S参数(进阶篇)
S参数是RF工程师/SI工程师必须掌握的内容,业界已有多位大师写过关于S参数的文章,即便如此,在相关领域打滚多年的人, 可能还是会被一些问题困扰着。你懂S参数吗? 图文解说S参数(基础篇) 请继续往下看...台湾…...

Sentinel源码阅读
基础介绍 Sentinel 的使用可以分为两个部分: 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配&…...

2023年浙江食品安全管理员考试真题题库及答案
百分百题库提供食品安全管理员考试试题、食品安全管理员考试预测题、食品安全管理员考试真题、食品安全管理员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、判断题 7.(重点)《餐饮服务食品安全…...

Webstorm 代码没有提示,uniapp 标签报错
问题 项目是用脚手架创建的: vue create -p dcloudio/uni-preset-vue my-project 打开之后,添加view标签警告报错的。代码也没有提示,按官方说法:CLI 工程默认带了 uni-app 语法提示和 5App 语法提示。 但是我这里就是有问题。…...

MySQL-Innodb引擎事务原理
文章目录1.事务介绍2 事务特性3. 事务的实现原理4 redo log 保证持久性5 undo log 保证原子性6 MVCC 概念6.1 隐藏字段6.2 版本链6.3 ReadView6.3.1readview 版本控制规则7 隔离性 实现7.2 隔离性- REPEATABLE READ 可重复读下8 一致性1.事务介绍 事务是一组操作的集合…...

Linux操作系统学习(了解环境变量)
文章目录环境变量初识除了上述介绍的PATH,还有一些常见的环境变量如:查看环境变量方法 :环境变量的基本概念:本地变量:环境变量初识 环境变量解释起来比较抽象,先看示例: #include <stdio.…...

数据分析思维(六)|循环/闭环思维
循环/闭环思维 1、概念 在很多的分析场景下,我们需要按照一套流程反复分析,而不是进行一次性的分析,也就是说这套流程的结果会成为该流程的新一次输入,从而形成一个闭环,此时的分析思维我们称之为循环/闭环思维。 常…...

C++:类和对象(下)
文章目录1 再谈构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字2 static成员2.1 概念2.2 特性3 友元3.1 友元函数(流插入(<<)及流提取(>>)运算符重载)3.2 友元类4 内部类5 匿名对…...
ASP.NET Core MVC 项目 AOP之IResultFilter和IAsyncResultFilter
目录 一:说明 二:IActionFilter同步 三:IAsyncActionFilter异步 一:说明 IResultFilter同步过滤器与IAsyncResultFilter异步过滤器常常被用作于渲染视图或处理结果。 IResultFilter同步过滤器执行顺序: 1:执行控制器中的构造函数,实例化控制器 2:执行具体的Acti…...

jstack排查cpu占用高[复习]
这样就可以看到占用CPU高的代码位置。 总结:就是先查到占用高的应用和具体的线程,然后根据线程到堆积信息查找即可。 不过堆栈信息非十进制,需提前把线程号转为十六进制。 这样就可以看到占用CPU高的代码位置。 总结:就是先查到…...

网络安全-Pyhton环境搭建
网络安全-Pyhton环境搭建 https://www.kali.org/get-kali/#kali-installer-images—kali官网下载地址 python这个东东呢 是目前来说最简单,方便的开源的脚本语言 广泛用于Web开发,AI,网站开发等领域 python要装2和3 为什么要安装两个版本…...

SpringBoot Mybatis 分页实战
pageInfo的属性 pageNum:当前页 pageSize:页面数据量 startRow:当前页首条数据为总数据的第几条 endRow:当前页最后一条数据为总数据的第几条 total:总数据量 pages:总页面数 listPage{}结果集 reasonable …...

计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性
计算机断层扫描结肠镜和全自动骨密度仪在一次检查中的可行性 Feasibility of Simultaneous Computed Tomographic Colonography and Fully Automated Bone Mineral Densitometry in a Single Examination 简单总结: 数据:患者的结肠镜检查和腹部CT检查…...

Java多级缓存是为了解决什么的?
前言 提到缓存,想必每一位软件工程师都不陌生,它是目前架构设计中提高性能最直接的方式。 缓存技术存在于应用场景的方方面面。从网站提高性能的角度分析,缓存可以放在浏览器,可以放在反向代理服务器,还可以放…...

MongoDB--》索引的了解及具体操作
目录 索引—index 索引的类型 索引的管理操作 索引的使用 索引—index 使用索引的原因:索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这…...

Python open()函数详解:打开指定文件
在 Python 中,如果想要操作文件,首先需要创建或者打开指定的文件,并创建一个文件对象,而这些工作可以通过内置的 open() 函数实现。open() 函数用于创建或打开指定文件,该函数的常用语法格式如下:file ope…...

CentOS Stream 9尝鲜安装教程
作者:IT圈黎俊杰 一、下载CentOS Stream 9安装介质 在CentOS官网可以下载到CentOS Stream 9的安装介质,正面列出ISO介质的下载链接地址: https://download.cf.centos.org/9-stream/BaseOS/x86_64/iso/CentOS-Stream-9-20221019.0-x86_64-dv…...

Ambire AdEx 2023 年路线图
Ambire AdEx 是为简化 web3 显示广告而建立的,领先于时代。到 2023 年,它将专注于服务用户需求,同时保持其作为区块链隐私解决方案的核心,反对传统的数字广告模式。 回顾 2022 年 2022 年,AdEx 网络处理了超过 1 亿次展…...

两种特征提取方法与深度学习方法对比的小型金属物体分类分析研究
本文讨论了用于对包括螺丝、螺母、钥匙和硬币在内的小型金属物体进行分类的两种特征提取方法的效率:定向梯度直方图 (HOG) 和局部二进制模式 (LBP)。首先提取标记图像的所需特征并以特征矩阵的形式保存。使用三种不同的分类方法(非参数 K 最近邻算法、支…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项
一、条形码识别改名使用教程 打开软件并选择处理模式:打开软件后,根据要处理的文件类型,选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件,就选择 “PDF 识别模式”;若是处理图片文件&…...

2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】
1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...
VUE3 ref 和 useTemplateRef
使用ref来绑定和获取 页面 <headerNav ref"headerNavRef"></headerNav><div click"showRef" ref"buttonRef">refbutton</div>使用ref方法const后面的命名需要跟页面的ref值一样 const buttonRef ref(buttonRef) cons…...
后端下载限速(redis记录实时并发,bucket4j动态限速)
✅ 使用 Redis 记录 所有用户的实时并发下载数✅ 使用 Bucket4j 实现 全局下载速率限制(动态)✅ 支持 动态调整限速策略✅ 下载接口安全、稳定、可监控 🧩 整体架构概览 模块功能Redis存储全局并发数和带宽令牌桶状态Bucket4j Redis分布式限…...
第6章:Neo4j数据导入与导出
在实际应用中,数据的导入与导出是使用Neo4j的重要环节。无论是初始数据加载、系统迁移还是数据备份,都需要高效可靠的数据传输机制。本章将详细介绍Neo4j中的各种数据导入与导出方法,帮助读者掌握不同场景下的最佳实践。 6.1 数据导入策略 …...