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

自旋锁

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

自旋锁的接口

自旋锁的接口和挂起等待锁的接口十分的相似,首先来看一个名为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进行枷锁这样就导致读者在枷锁的时候被挂起等待,当写者先运行的时候就会导致第一个运行起来的读者无法申请到锁从而被挂起等待,这样就做到了读者和写者之间的互斥,那么这就是读写锁的大致实现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DeCLIP 论文阅读

DeCLIP:supervision exists everywhere:a data efficient contrastive language-image pre-training paradigm 贡献: 论文是为了充分利用单模态和多模态,充分利用单模态特征用自监督(SIMSAM和MLM),多模态用图像文本对…

P6入门:项目初始化4-项目详情之预算日志及汇总Budget

前言 使用项目详细信息查看和编辑有关所选项目的详细信息,在项目创建完成后,初始化项目是一项非常重要的工作,涉及需要设置的内容包括项目名,ID,责任人,日历,预算,资金,分类码等等&…

ELK之Logstash解析时间相差8h的问题

一、问题描述 服务器当前时间为:2022年 06月 28日 星期二 11:24:22 CST 而logstash解析的时间为2022-06-28T03:15:25.545Z与实际时间相差8h 一、解决办法: 需改logstash的配置文件: 原理就是:定义一个中间变量timestamp&…

Unity如何保存场景,如何导出工程文件/如何查看保存位置?【各版本通用】

如何保存场景? 在unity中CtrlS 或者File—>Save 输入你要保存的场景名【建议保存在Scenes文件夹下】 下图,保存场景不在Scenes文件夹下: 下图,保存在Scenes文件夹下: 下图,保存完成 如何导出工程文…

nginx配置和热部署实践

目录 一、nginx配置文件 1.配置文件 2.nginx配置文件语法 3.include 二、nginx.conf参数 1.user参数 2.nginx.conf重要的指令块 3.nginx命令行 三、nginx热部署功能实践 1.热部署的特点 2.大致流程 3.环境准备 4.备份旧nginx二进制文件 5.下载编译安装新的nginx …

Mac电脑配置Flutter开发环境

1.进入官网下载页: Flutter SDK releases | Flutter 可以看到有 Windows、macOS、Linux三种系统的下载包 选择macOS,然后点击下载 Stable channel(稳定版)中的最新版本,下载完成后可以移动到资源库Library中。 2.下载…

Unity Input System最简单使用

开始学的是 Input Manager 比较好理解,Input System却不好理解,教程也找了很多,感觉都讲的不清楚,我这里做一个最简单的用 Input System 添加鼠标左键和右键的效果。 1. 安装 Input System 包 首先这个功能不是内置的&#xff0…

Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例

Flutter笔记 使用Flutter构建响应式PC客户端/Web页面-案例 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/detai…

红黑树,AVLTree树(平衡二叉树)迭代器原理讲解

红黑树,AVLTree树底层实现逻辑都是平衡二叉树(AVLTree高度平衡,红黑树以某种规则平衡),但终究不像链表的迭代器那样逻辑简单。 简单叙述以下,二叉树上面迭代器的运行逻辑,根据下面的图&#xff…

leetcode-链表经典题

1.反转单链表 206. 反转链表https://leetcode.cn/problems/reverse-linked-list/这里我们使用创建一个变量cur来遍历原链表,再创建一个新节点newnode,首先使用一个循环来遍历原链表,cur为NULL是循环结束,每次进入循环将cur的下一…

.mallab勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复

导言: .mallab勒索病毒是一种极具威胁性的数字病毒,通过高级加密算法深度侵袭用户文件,迫使受害者支付赎金以获取解密密钥。了解其侵害方式和对抗手段对数字安全至关重要。数据的重要性不容小觑,您可添加我们的技术服务号&#x…

threejs(12)-着色器打造烟雾水云效果

一、自己封装水波纹效果 src/main/main01.js import * as THREE from "three";import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import gsap from "gsap"; import * as dat from "dat.gui"; import ver…

【文件IO】

文章目录 File常见方法和属性属性构造方法方法 InputStream方法FileInputStream OutputStream利用 OutputStreamWriter 进行字符写入 总结按字节读取数据按字节写入数据按字符读取数据按字符写入数据 File常见方法和属性 属性 修饰符及类型属性说明static StringpathSeparato…

网络安全(黑客技术)-高效自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…

思科设备静态路由配置

一、静态路由基本知识 路由器的主要功能就是用来转发IP 数据包以使数据包到达正确的目的主机。可以想象数据包到达路由器就像一辆汽车开到十字路口,路由表就类似路标,列出可能到达的目的地,以及应该选择哪条路到达目的地。 路由器必须要有相应…

Linux - 基础IO(重定向 - 重定向模拟实现 - shell 当中的 重定向)- 下篇

前言 上一篇博客当中,我们对 文件 在操作系统当中是 如何就管理的,这个问题做了 详细描述,本篇博客将基于上篇 博客当中的内容进行 阐述,如有疑问,请参考上篇博客: Linux - 基础IO(Linux 当中…

应用层——HTTP协议

文章目录 HTTP协议1.HTTP简介2.认识URL3.urlencode和urldecode4.HTTP协议格式(1)HTTP请求协议格式(2)HTTP响应协议格式 5.HTTP的方法6.HTTP的状态码7.HTTP常见的Header8.Cookie和Session HTTP协议 1.HTTP简介 HTTP(Hy…

mac安装brew

命令 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"如图 选择下载源,进行安装 安装完成 验证

计算机毕业设计 基于SpringBoot的实训管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

【零基础小白也能轻松学会】3DMAX编织建模教程

有没有想过这些木质材料是如何在椅子上相互交织的?复杂吗?也许是也许不是……本教程将指导您一步一步地以任何形式提出自己的复杂编织图案。本教程将重点关注建模部分,并让您从那里开始发挥想象力。 1.首先创建一个新平面(长度55&…