linux入门---自旋锁和读写锁

news2024/11/19 15:21:34

自旋锁

首先通过一个例子来带着大家理解自旋锁,在生活中大家肯定都等过人比如你们一家人准备出去玩可是出发的时候妻子发现自己还没有化妆于是连忙赶回了家这个时候其他人就得在楼下等着,但是这个等又分为两种情况第一种是真的在楼下等其他的什么事都没有干,那么这种情况就一定非常的枯燥无聊,所以你会隔三差五的打电话问你的妻子好了没,下楼了没,化妆化完了没,第二种情况就是老婆在家里化妆但是你没有在楼下等,你干其他的事情去了,你跟妻子说画完状之后跟我打个电话我立马回到楼下来接你,因为你干其他的事情去了所以不会干其他的事情也就不会不停的打电话来催你老婆了。那么这是生活上的两种情况,程序中的锁也是相同的场景,我们之前用锁的时候会发现当申请不到锁的时候该线程就会挂起等待,那么这就是上面等人的第二个场景,而我们待会要介绍的自旋锁就是上面的第一个场景,当没有申请到锁资源的时候自旋锁就会不停的访问锁好了没就绪了没直到申请到了为止,那么这里就有一个问题:是什么决定了等待的方式?因为已经被线程访问的临界资源决定了其他线程要进行等待,所以一个成功申请临界资源的线程在临界区呆的多长时间决定了等待的方式,如果等待的时间较长就选择挂起等待锁也就是我们之前用的锁,如果等待的时间较短就使用自旋锁,那如何判断时间的长短呢?答案是没有办法判断的这个是一个相对的东西,是没有绝对的判断标准的可以通过两者都用的方式测试一下效率来做最后的判断,但是自旋锁我们是不推荐使用的,因为挂起等待虽然看上去会慢点但是一旦自旋锁评估失误,他会大量的消耗资源比如说挂起等待的时候出现死锁了不起就是两者都挂起等待,但是自旋锁一旦出现了类似于死锁的情况就会不停的检测锁的状态但是却没有一个人释放锁会造成大量的资源浪费,所以自旋锁很危险不建议使用。

自旋锁的接口

自旋锁的接口和挂起等待锁的接口十分的相似,首先来看一个名为pthread_spin_lock函数
在这里插入图片描述
可以看到这个函数需要一个pthread_spinlock_t类型的指针,那么这个pthread_spinlock_t就是上面说的自旋锁,在使用自旋锁之前先定义一个自旋锁变量,然后再使用pthread_spin_init函数对其进行初始化:
在这里插入图片描述
第一个参数表示对哪把锁初始化,第二个参数直接传递0就行,当不需要用这个锁对象之后就可以使用pthread_spin_destroy对其进行销毁,当不需要用这把锁的时候就可以使用pthread_spin_unlock将其解锁,当需要这把锁进行枷锁的时候就可以使用函数pthread_spin_lock函数:
在这里插入图片描述
当申请锁失败之后得的动作需要我们自己做的话就可以使用pthread_spin_trylock函数,如果不想自己做的话就使用函数pthread_spin_lock函数,那么这就是自旋锁的接口。

读者写着问题

在编写多线程的时候有一种情况是十分常见的。那就是有些公共数据修改的机会比较少,相比较改写它们读的机会反而高的多。通常而言在读的过程中往往伴随着查找的操作,中间耗时很长。给这种代码段加锁会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有那就是读写锁,我们可以把线程分为两类一个是读者线程一个写者线程,在处理读者写着问题的过程中我们也得维护3 2 1原则,也就是3种关系读者和读者的关系,写者和写者的关系,读者和写者的关系,写者和写者之间一定是互斥的关系因为两个线程在写的时候可能会同一块空间进行写入,写者和读者之间也是互斥关系,因为写者还没有写完的时候读者就跑过来读取,那么这个时候读取的数据肯定是不完整的,并且写者写完数据之后可能接连着就对数据进行修改读者还来不及进行读取,所以写者和读者之间还有个同步的关系,因为读者不会对数据进行修改,多个读者在读取数据的时候也不会出现线程安全问题就好比大家上课看老师ppt一样每个人都能读,所以读者和读者之间没有关系,2就表示两个角色也就是读者和写着,1就表示的是共享资源,那这里就有一个问题这里的读者和写着模型跟消费者生产者消费者之间有什么区别呢?答案就是消费者会拿走数据,一个消费者线程拿走数据之后其他消费者是看不到这个数据的,但是读者不一样读者只会拷贝不会拿走,所以读者和读者之间没有关系,所以读者写着模型适合于:一次发布,很长时间不会修改,大部分都是被读取的场景,比如说新闻,报纸,小说等等都是少写多读的场景。

读者写着的接口

首先来看函数pthread_rwlock_init函数,这个函数也跟之前学的mutex锁函数类似:
在这里插入图片描述
首先使用读写锁之前也得创建一个读写锁对象也就是pthread_rwlock_t对象,然后就可以使用pthread_rwlock_init对这个对象进行初始化,当不再使用这个对象之后就可以使用pthread_rwlock_destory函数将对象销毁,在枷锁的时候如果你是读者就使用pthread_rwlock_rdlock函数进行枷锁
在这里插入图片描述
如果你是写着线程你就使用pthread_rwlock_wrlock函数对其进行枷锁:
在这里插入图片描述
不管你是写着还是读者,当你想要解锁的时候都可以使用函数pthread_rwlock_unlock
在这里插入图片描述
如果当前没有枷锁,那么读者和写者都能正常的申请到锁,如果当前写者申请到了锁那么其他的写者线程和读者线程就申请不到锁,如果读者线程申请到了锁那么其他的读者线程也能申请到锁,但是写者线程是申请不到锁,我们可以通过下面的图片来了解:
在这里插入图片描述

读写锁的原理

这里我们用伪代码的方式来带着大家理解锁的原理,首先对于写锁我们可以认为里面就一个挂起等待锁:

//写着锁
pthread_mutex_t wrlock

当写锁要枷锁的时候就直接对挂起锁进行枷锁,解锁的时候也是直接对挂起锁进行解锁就行

//写着锁枷锁
lock(&wrlock);

//写着锁解锁
unlock(&wrlock);

而读者锁就不一样,我们可以将他的内部看成一把挂起锁和一个计数器

//读者锁
pthread_mutex_t rdlock;
int read_count=0;

因为有计数器的存在读者锁在挂起的时候会先对自己的挂起锁进行枷锁,然后再对计数器进行加一

lock(&rdlock);
read_count++;

然后我们就判断一下当前计数器的值是否为1,如果为1的话就表明当前是第一次申请读者锁得防止写者往共享区中写数据,所以得将写着锁中的wrlock锁起来:

lock(&rdlock);
read_count++;
if(read_count==1)
{lock(&wrlock)}

将写者锁枷锁起来后就可以将自己的rdlock进行解锁然后对共享数据进行访问

lock(&rdlock);
read_count++;
if(read_count==1)
{lock(&wrlock)}
unlock(&rdlock)

//读取数据

在解锁的时候就是先对rdlock进行枷锁然后对计数器的值进行减一,如果计数器的值为0了就表明一个读者都没有了,那么这个时候就可以将写者内部的锁进行解锁最后将rdlock进行解锁即可:

//读者锁解锁
lock(&rdlock)
read_count--;
if(read_count==0)
{unlock(&wrlock)}
unlock(&rdlock);

那么这就是读者写着锁内部实现的伪代码,当读者先运行的时候会对wrlock进行枷锁这样就导致读者在枷锁的时候被挂起等待,当写者先运行的时候就会导致第一个运行起来的读者无法申请到锁从而被挂起等待,这样就做到了读者和写者之间的互斥,那么这就是读写锁的大致实现。

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

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

相关文章

Nginx:不同域名访问同一台机器的不同项目

Nginx很简单就可以解决同一台机器同时跑两个或者多个项目,而且都通过域名从80端口走。 以Windows环境下nginx服务为例,配置文件nginx.conf中,http中加上 include /setup/nginx-1.20.1/conf/conf.d/*.conf;删除server部分,完整如…

RT-Thread Studio开发 新手入门

文章目录 前言一、RT-Thread Studio 与 STM32CubeMX 下载安装二、新建工程三、点亮LED灯四、按键中断五、串口通信六、OLED显示 前言 软件开发环境:RT-Thread Studio、STM32CubeMX 硬件:STM32F407ZGT6 一、RT-Thread Studio 与 STM32CubeMX 下载安装 …

【图像处理:OpenCV-Python基础操作】

【图像处理:OpenCV-Python基础操作】 1 读取图像2 显示图像3 保存图像4 图像二值化、灰度图、彩色图,像素替换5 通道处理(通道拆分、合并)6 调整尺寸大小7 提取感兴趣区域、掩膜8 乘法、逻辑运算9 HSV色彩空间,获取特定…

哈希表之闭散列的实现

闭散列实现哈希表 在闭散列实现哈希表中,我们选择线性探测法来解决哈希冲突。在哈希表的简介部分,我们已经介绍过线性探测法啦! 线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止…

【Springboot】基于注解式开发Springboot-Vue3整合Mybatis-plus实现分页查询(二)——前端el-pagination实现

系列文章 【Springboot】基于注解式开发Springboot-Vue3整合Mybatis-plus实现分页查询—后端实现 文章目录 系列文章系统版本实现功能实现思路后端传入的数据格式前端el-table封装axois接口引入Element-plus的el-pagination分页组件Axois 获取后台数据 系统版本 后端&#xf…

Day58_《MySQL索引与性能优化》

文章目录 一、SQL执行顺序二、索引简介1、关于索引2、索引的类型Btree 索引Btree 索引 三、Explain简介四、Explain 详解1、id2、select_type3、table4、type5、possible_keys6、key7、key_len8、ref9、rows10、Extra11、小案例 五、索引优化1、单表索引优化2、两表索引优化3、…

Spring Boot 整合xxl-job实现分布式定时任务

xxl-job介绍 XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 xxl是xxl-job的开发者大众点评的许雪里名称的拼音开头。 设计思想 将调度行为抽象形成“调度…

multilinear多项式承诺方案benchmark对比

1. 引言 前序博客有: Lasso、Jolt 以及 Lookup Singularity——Part 1Lasso、Jolt 以及 Lookup Singularity——Part 2深入了解LassoJolt Lasso lookup中,multilinear多项式承诺方案的高效性至关重要。 本文重点关注4种multilinear多项式承诺方案的实…

linux 不同用户不同jdk

0、 解压一个新版本的jdk 1、 检查root用户下的环境变量,是否配置了JAVA_HOME,基于这个变量再配置的PATH变量是实现切换的前提。 2、 创建新用户 adduser jdk11 passwd jfjfjfjfjfjfj123 3、 编辑改用下的 .bashrc 文件 执行命令进行编辑&#xff0…

【Nginx】深入浅出搞懂Nginx

Nginx是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。 反向代理服务器? 经常听人说到一些术语,如反向代理,那么什么是反向代理&a…

BGP基本配置实验

目录 一、实验拓扑 二、实验需求 三、实验步骤 1、IP地址配置 2、内部OSPF互通,配置OSPF协议 3、BGP建立邻居关系 4、R1和R5上把业务网段宣告进BGP 5、消除路由黑洞,在R2、R4上做路由引入 6、业务网段互通 一、实验拓扑 二、实验需求 1、按照图…

开发者测试2023省赛--UnrolledLinkedList测试用例

测试结果 官方提交结果 EclEmma PITest 被测文件UnrolledLinkedList.java /** This source code is placed in the public domain. This means you can use it* without any restrictions.*/package net.mooctest;import java.util.AbstractList; import java.util.Collectio…

担忧CentOS停服?KeyarchOS系统来支撑

担忧CentOS停服?KeyarchOS系统来支撑 近年发生的“微软黑屏门”、“微软操作系统停更”、“棱镜门”、“中兴华为”等安全事件,敲响了我国 IT 产业的警钟,建立由我国主导的 IT 产业生态尤为迫切。对此,我国信息技术应用创新行业乘…

数字媒体技术基础之:分辨率

分辨率 Resolution,中国大陆译为“分辨率”,中国香港地区、中国台湾地区分别译为“解像度”和“解析度”,泛指测量设备对细节的分辨能力。 ◆ ◆ ◆ 图像尺寸 在数字图像处理中,像素 Pixel是一个无具体物理尺寸的抽象单位。 一张…

序列化模块-json和pickle

一、json json是所有语言都通用的一种序列化格式 ,只支持 列表、 字典、 字符串、 数字 , 字典的key必须是字符串 1、dumps、loods # 在内存中做数据转换 : # durps 数据类型 转成 字符串 序列化 # loods 字符串 转成 数据类型 反序…

基于STC12C5A60S2系列1T 8051单片机定时器/计数器应用

基于STC12C5A60S2系列1T 8051单片机定时器/计数器应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍STC12C5A60S2系列1T 8051单片机定时器/计数器介绍STC12C5A60S2系…

No179.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

C++算法:完美矩形

题目 给你一个数组 rectangles ,其中 rectangles[i] [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。 如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则&#xf…

C语言基础篇3:函数

1 函数简介 C源程序是由函数组成的,一个程序往往由多个函数组成,函数是程序实现模块化变成的基本的单元,一般是为了完成某一个特定的功能,相当于其他语言中的子程序。一个较大程序的各项功能都是由各个子程序共同完成的&#xff0…

【Seata源码学习 】 AT模式 第一阶段 @GlobalTransaction的扫描

1. SeataAutoConfiguration 自动配置类的加载 基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigurationio.seata.spring.boot.aut…