Linux:锁和线程同步的相关概念以及生产者消费者模型

news2024/11/17 10:47:18

文章目录

  • 加锁的基本原则
  • 死锁
    • 死锁的概念
    • 死锁的条件
  • 线程同步
  • 生产者消费者模型
    • 模型的理解
  • 理解cp问题
  • 条件变量

本篇总结的是关于Linux中锁的相关概念以及生产者消费者模型

加锁的基本原则

加锁的基本原则:谁加锁谁解锁,不要把加锁和解锁这样的操作放在两个线程中

死锁

死锁的概念

下面讲述死锁的一种情况,进而对于死锁有一个较为清楚的认知:

在这里插入图片描述
上图展示的是死锁的其中一个场景,对于这个代码块来说,想要访问这部分资源必须需要两个锁,一个是lock1,一个是lock2

那此时有两个线程A和B,对于线程A来说,它现在持有一把锁lock1,对于线程B来说它持有一把锁lock2,但此时这两个线程都无法进入对应的代码块中,此时线程A要访问这块资源,发现条件不足,少一把锁,于是被挂起,线程B要访问这块资源,发现条件不足,少一把锁,于是被挂起,基于这样的原因,这两个线程在之后的每一次被调度都会被阻塞,这就是一个最基本的死锁问题

死锁的条件

互斥条件:一个资源每次只能被一个执行流使用
请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺
循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系

对比上述的四个条件,再次回到刚才的这个死锁场景

  1. 互斥条件:代码中间的这部分资源只能被线程A和B当中的一个进行访问,构成了互斥条件
  2. 请求和保持:线程A和B发生阻塞的时候,不会对于当前它们所持有的锁进行释放,而是占用了现有的这个锁,直到下次被调度
  3. 不剥夺条件:线程A不能去把线程B当前所持有的锁剥夺下来供自己使用
  4. 循环等待:线程A和B交替对于锁的申请判断的逻辑构成了一个环的概念

所以,想要构成死锁,必须要满足上述的这四个条件,只要有一个不满足就不应构成死锁,因此也有了另外一个话题,想要破坏死锁,本质上来说只要破坏了这四个条件中的一个就可以了

线程同步

前面讲解了线程互斥的基本原理,那么本节主要讲解关于线程同步的原理,对于线程同步的理解,先给出下面的使用场景:

现有一个线程,拥有一把锁,所以它在以很高的强度对于这个资源进行访问,但是很不幸,处于一些原因,它的访问每次都是无效的,而由于规则的指定失误,这个线程每次都能访问到这个资源,而其他的线程却无法访问到这个资源,这样就造成了线程饥饿的现象出现,那为了解决这样的问题,就给出了线程同步的概念

线程同步是指在多线程编程中,控制多个线程之间的执行顺序和共享资源的访问,以确保数据的一致性和正确性,例如在上面的情景中,可以制定特定的规则,当前线程结束后,必须进行某个队列中进行排队,当排队结束后才能继续进行访问,这样本质上就解决了对于一份共享资源被同一个线程高强度的重复访问,就会造成所谓线程饥饿的现象出现,换句话说,线程同步就是如何合理的使用资源解决线程饥饿的问题,也可以说是让临界资源在使用安全的前提下,让多线程的执行具有一定的顺序性,这个就是所谓线程同步的基本概念

生产者消费者模型

先上定义:
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的

模型的理解

对于这个模型的理解,首先从生活的场景入手:在生活中,超市就是一个很经典的生产消费模型,每一个消费者想要获取生产者生产出来的物品,而生产者生产出来的问题要放到超市,超市再把这些内容卖给消费者,就是这样的一个过程

对于这个模型的理解来说,可以把这个生产者看成是线程,而消费者也是线程,那生产者生产的内容交给消费者,这个过程该如何理解?实际上直接把计算机中的数据当成商品就可以

生产者消费者的这个模型,本质上来说就是执行数据流动的过程,把数据由一批线程交由另外一批线程,可以看成是数据流动,也可以是理解为通信的概念,但现在我们抛开这个超市本身的问题,对于供货商来说,想要把自己的商品交到超市里面,所以超市对于供货商来讲本身就是一种临界资源,消费者要到超市中去消费,前提要保证这个过程是安全的,对应到线程的概念来说,就是一批线程要把数据交给另外一批线程,在这个交付的过程中务必要保证是线程安全的

那如何理解线程安全?下面我给出一个线程不安全的例子,比如说现在超市正在供货,但当这个货还没放到货架的时候就被消费者拿走了,那对于超市来说,它其实并不知道这个东西到底是否存放到了货架中,甚至可能在进行统计数量的时候只是统计了放置到货架上的内容,并没有统计这个用户前面拿走的这个内容,这就可以看成是一个数据不安全的问题,对应到线程中也是如此,如果产生了上述这样的类似的问题,那就可以把这个过程看成是不安全的现象

有了上述的概念,下面来理解三个关系

  1. 生产者和生产者之间的关系:竞争并且互斥,一个货架只能放一种货品,并且总量是保证的,一个供货商的东西放多了,其他供货商自然就没了,并且在一个厂商放东西的时候另外一个不能也放,这叫做互斥
  2. 消费者和消费者之间的关系:竞争并且互斥,原理和上述相似,货架总共就这么多东西,拿的多的自然就有拿的少的
  3. 生产者和消费者之间的关系:互斥并且同步,具体理解如下:

互斥性:互斥性确保在同一时间只能有一个线程(生产者或消费者)访问共享资源(缓冲区)。这意味着当一个线程正在对缓冲区进行生产或消费操作时,另一个线程不能同时进行相同的操作。这样可以避免数据竞争和数据不一致的问题。

同步性:同步性确保生产者和消费者之间的操作是协调一致的,即当生产者生产了数据并放入缓冲区后,消费者必须能够及时地从缓冲区中取出数据进行处理;反之,当缓冲区为空时,消费者必须等待生产者生产数据。同样地,当缓冲区已满时,生产者必须等待消费者消费数据

理解cp问题

CP 问题通常是指"Consumer-Producer"(消费者-生产者)问题,那下面先举一个这样的例子

假设现在有函数调用,在main函数中函数执行的很快,但是如果跳转到函数体内部,就执行的很慢,那么此时外部的这个main函数就必须要等待内部的函数调用执行结束后才能进行继续的调用,那这个过程就是普通的单线程可能会经常遇到的一个情景

那能不能设计这样的一个情景,使得这个执行快的这部分一直很快,慢的部分一直很慢,两个执行流互不干扰呢?那cp问题就可以解决这样的情景,cp问题的主要目的就是实现一个多执行流之间的执行解耦问题,线程在不断的把数据很快的输送到一个地方,而另外一批线程正在慢慢的进行数据的计算等,这个逻辑和前面的超市的逻辑一样,如果按照单线程的理解来说,供货商的生产速度很快,但是消费者消费的很慢,供货商必须等消费者消费结束后才能继续供货,这样必然会导致效率的问题,因此就有了生产消费模型,供货商快速的生产,把货放到超市里面,而消费者只需要慢慢的对这些货进行消费就可以了,把供货商和消费者之间的关系进行了一个解耦,这样就实现了想要形成的一个状态

换句话说这是一个忙闲不均的问题,生产的这一端很忙,在不停的向这段空间中扔数据,而消费的却闲,但不影响生产继续生产,这就是因为有这段空间带来的好处

条件变量

在生产消费模型中,条件变量是一个很重要的概念,再以超市为例,当货物还没有就绪的时候,消费者如果要在超市中申请货物是申请不到的,而频繁的进行申请可能还会带来影响供货的速度,那为了解决这样的问题就引入了条件变量的概念,可以把条件变量理解为一个提醒器,在货物就绪的时候就提醒消费者,可以进行消费了,这样就避免了消费者在进行频繁申请却没有成果带来的这样的弊端

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

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

相关文章

Java线程池ThreadPoolExecutor源码阅读

文章目录 概述线程池提交任务流程线程池提交任务源码阅读 源码阅读属性字段工作线程worker 线程池方法runWorker(Worker w) 运行工作线程getTask() 获取任务tryTerminate() 尝试终止线程池interruptWorkers、interruptIdleWorkers 中断工作线程reject(Runnable command) 拒绝任…

数组名的理解,看这一篇就够了!!!

!!!以下是会涉及到的知识的讲解: 一:数组名的理解: 数组名是数组首元素的地址,但是有2个例外: 1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个…

LeetCode59:螺旋矩阵Ⅱ

题目描述 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 输入:n 3 输出:[[1,2,3],[8,9,4],[7,6,5]] 代码 class Solution { public:vector…

查看pip当前关联python版本及位置

好久没用python了,把各种pip指向的环境忘光光啦,这里记录一下查看pip当前关联的python版本及位置的方法: pip -V结果: 我一般不用这个版本的python,去环境变量看了一下,原来是anaconda的Scripts自带pip&a…

Vue class和style绑定:动态美化你的组件

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

EB tersos 24.0.1 添加MCU模块失败

1、问题: 新建工程,添加MCU模块总是失败,错误信息如下: 2、解决方案 创建工程时只保留Resource模块,直接点击Finish,其他模块之后再添加 在工程创建成功后再单独添加需要的模块

StableDiffusion3 官方blog论文研究

博客源地址:Stable Diffusion 3: Research Paper — Stability AI 论文源地址:https://arxiv.org/pdf/2403.03206.pdf Stability.AI 官方发布了Stable diffusion 3.0的论文研究,不过目前大家都沉浸在SORA带来的震撼中,所以这个水…

力扣530. 二叉搜索树的最小绝对差

思路1&#xff1a;中序遍历&#xff0c;递归排序成有序数组&#xff1b;因为是有序&#xff0c;只需要求相邻两个值的最小差值。 class Solution {ArrayList <Integer> list new ArrayList();int ans 100001;//题目最大 100000public int getMinimumDifference(TreeNo…

docker学习笔记——Dockerfile

Dockerfile是一个镜像描述文件&#xff0c;通过Dockerfile文件可以构建一个属于自己的镜像。 如何通过Dockerfile构建自己的镜像&#xff1a; 在指定位置创建一个Dockerfile文件&#xff0c;在文件中编写Dockerfile相关语法。 构建镜像&#xff0c;docker build -t aa:1.0 .(指…

异步编程实战:使用C#实现FTP文件下载及超时控制

博客标题: 异步编程实战&#xff1a;使用C#实现FTP文件下载及超时控制 如果你的函数不是async&#xff0c;你仍然可以实现相同的超时功能&#xff0c;但你将不得不依赖更多的同步代码或使用.Result或.GetAwaiter().GetResult()来阻塞等待任务完成&#xff0c;这可能导致死锁的风…

Breach-2.1

靶场环境说明 该靶场是静态IP地址&#xff0c;需要更改网络配置&#xff0c;攻击机kali做了两张网卡&#xff1b; 信息收集 # nmap -sT --min-rate 10000 -p- 192.168.110.151 -oN port.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-02-09 10:47 CST Stats: 0:00:…

java通过poi-tl生成word

我看公司之前做电子合同&#xff0c;使用TIBCO jaspersoft做的报表模板&#xff0c;如果是给自己公司开发或者给客户做项目&#xff0c;这个也没有什么&#xff0c;因为反正模板是固定的&#xff0c;一次性开发&#xff0c;不用担心后续的问题。即使后期有调整&#xff0c;改一…

深入解读 Elasticsearch 磁盘水位设置

本文将带你通过查看 Elasticsearch 源码来了解磁盘使用阈值在达到每个阶段的处理情况。 跳转文章末尾获取答案 环境 本文使用 Macos 系统测试&#xff0c;512M 的磁盘&#xff0c;目前剩余空间还有 60G 左右&#xff0c;所以按照 Elasticsearch 的设定&#xff0c;ES 中分片应…

总结:Spring创建Bean循环依赖问题与@Lazy注解使用详解

总结&#xff1a;Spring创建Bean循环依赖问题与Lazy注解使用详解 一前提知识储备&#xff1a;1.Spring Bean生命周期机制&#xff08;IOC&#xff09;2.Spring依赖注入机制&#xff08;DI&#xff09;&#xff08;1&#xff09;Autowired注解标注属性set方法注入&#xff08;2&…

面具安装LSP模块时提示 Unzip error错误的解决办法

面具(Magisk Delta)安装LSP模块时提示 Unzip error错误的解决办法 ​​ 如果前面的配置都正常的话&#xff0c;可能是LSP版本有问题重新去Github下载一个最新版的吧&#xff1b;我是这么解决的。 我安装1.91那个版本的LSP就是死活安装不上&#xff0c;下载了1.92的版本一次就…

Golang-channel合集——源码阅读、工作流程、实现原理、已关闭channel收发操作、优雅的关闭等面试常见问题。

前言 面试被问到好几次“channel是如何实现的”&#xff0c;我只会说“啊&#xff0c;就一块内存空间传递数据呗”…所以这篇文章来深入学习一下Channel相关。从源码开始学习其组成、工作流程及一些常见考点。 NO&#xff01;共享内存 Golang的并发哲学是“要通过共享内存的…

⭐每天一道leetcode:83.删除排序链表中的重复元素(简单;链表遍历、删除经典题目)

⭐今日份题目 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例1 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 示例2 输入&#xff1a;head [1,1,2,3,3] 输出&#xff1a;[1,2,3] …

Linux 进程程序替换

&#x1f493;博主CSDN主页:麻辣韭菜-CSDN博客&#x1f493;   ⏩专栏分类&#xff1a;http://t.csdnimg.cn/G90eI⏪   &#x1f69a;代码仓库:Linux: Linux日常代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d;&#x1f5…

考研经验|如何从考研失败中走出来?

对我来说&#xff0c;太丢人了 其实我在本科的时候在同学眼中&#xff0c;一直很优秀&#xff0c;每年奖学金必有我的&#xff0c;国家励志奖学金&#xff0c;国家奖学金&#xff0c;这种非常难拿的奖学金&#xff0c;我也拿过&#xff0c;本科期间学校有一个公费去新西兰留学的…

美化console

console简介 控制台&#xff08;Console&#xff09;是JS开发里最重要的面板&#xff0c;主要作用是显示网页加载过程中产生各类信息,我们经常使用console.log()这个函数在控制台打印一些东西 但是,console这个对象不仅仅有log这个函数,还有很多其他的函数,如下 console.de…